2.30. Включения (comprehensions)¶
Включение (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 – результатом является само значение включения.
Ведущее выражение производит каждый элемент; конструкция 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, когда:
Тело требует более одного оператора (во включение помещается ровно одно выражение).
Тело имеет побочные эффекты (вывод, запись в файл) – включения предназначены для построения коллекции, а не для выполнения действий.
У фильтра или преобразования так много частей, что включение больше не читается слева направо.