2.30. Включення

Включення (comprehension) будує новий список, множину, словник або генератор з існуючого ітерованого об’єкта в одному виразі. Це заміна поширеного шаблону, коли починають з порожнього контейнера та додають елементи в циклі.

2.30.1. Включення списків

squares = [x * x for x in range(5)]
print(squares)

Виведення:

[0, 1, 4, 9, 16]

Той самий цикл у розгорнутому вигляді:

squares = []
for x in range(5):
    squares.append(x * x)

Форма включення є одним виразом, що будує список на місці. Немає squares = [] і немає .append – результатом є значення самого включення.

The expression "[f(x) for x in xs if cond]" annotated: the leading expression is the result, the for clause names the loop variable, the if clause filters which items are kept.

Провідний вираз породжує кожен елемент; оператор for визначає змінну циклу; необов’язковий if фільтрує елементи.

2.30.2. Фільтрація за допомогою if

Необов’язковий оператор if залишає лише елементи, що відповідають умові:

evens = [x for x in range(10) if x % 2 == 0]
print(evens)

Виведення:

[0, 2, 4, 6, 8]

Фільтр виконується перед провідним виразом – спочатку перевіряється x % 2 == 0; лише відповідні значення потрапляють до x у виведенні.

2.30.3. Включення словників та множин

Та сама структура працює зі словниковими та множинними літералами.

Включення словника має пару key: value перед for:

squares = {x: x * x for x in range(5)}
print(squares)

Виведення:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Включення множини використовує фігурні дужки та один вираз:

unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)

Виведення:

{1, 2}

2.30.4. Генераторні вирази

Круглі дужки породжують генераторний вираз замість списку. Значення обчислюються по одному, на вимогу:

total = sum(x * x for x in range(1000))

Список з мільйона елементів ніколи не будується. Значення надходять по одному до sum(), який додає їх і відкидає кожне по мірі обробки.

Генераторні вирази є правильним вибором при передачі значень до функції-редуктора (sum(), max(), any(), all()) або будь-якого іншого коду, що споживає ітератор – вони економлять пам’ять, яку зайняв би еквівалентний список.

2.30.5. Коли не варто використовувати включення

Включення є лаконічними, але не завжди більш зрозумілими. Використовуйте звичайний цикл for, коли:

  • Тіло потребує більше одного оператора (включення вміщує рівно один вираз).

  • Тіло має побічні ефекти (виведення, запис у файл) – включення призначені для побудови колекції, а не для виконання дій.

  • Фільтр або перетворення мають так багато частин, що включення більше не читається зліва направо.