Списковые, словарные и множественные включения
Списковое включение
Вместо цикла с append:
squares = []
for x in range(10):
squares.append(x * x)
print(squares)
squares = [x * x for x in range(10)] # то же самое одной строкой
print(squares)
Общая форма: [выражение for элемент in итерируемое if условие].
words = ["Python", "is", "AWESOME", "and", "fun"]
print([w.lower() for w in words])
print([w for w in words if len(w) > 3])
print([len(w) for w in words if w.isupper()])
Условие до и после for
nums = [-2, 5, -1, 8]
print([x for x in nums if x > 0]) # фильтр: if после for
print([x if x > 0 else 0 for x in nums]) # преобразование: тернарный оператор до for
Как не перепутать
if после for — отбрасывает элементы (результат короче). if ... else до for — выбирает значение для каждого элемента (длина та же).
Вложенные циклы
Порядок for — такой же, как во вложенных циклах:
pairs = [(x, y) for x in range(3) for y in "ab"]
print(pairs)
# эквивалент:
# for x in range(3):
# for y in "ab":
# pairs.append((x, y))
matrix = [[1, 2, 3], [4, 5, 6]]
flat = [x for row in matrix for x in row]
transposed = [[row[i] for row in matrix] for i in range(3)]
print(flat, transposed)
Словарные и множественные включения
words = ["кот", "собака", "ёж", "кот"]
lengths = {w: len(w) for w in words} # dict
unique_lengths = {len(w) for w in words} # set
inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}
print(lengths, unique_lengths, inverted)
Генераторные выражения
С круглыми скобками получается не кортеж, а генератор — ленивая последовательность, которая вычисляет элементы по одному:
gen = (x * x for x in range(5))
print(gen)
print(next(gen), next(gen), list(gen)) # элементы выдаются по требованию
print(list(gen)) # генератор одноразовый — уже пуст
print(sum(x * x for x in range(1_000_000))) # без промежуточного списка в памяти
print(any(n > 100 for n in [5, 300, 7])) # останавливается на первом True
Если генераторное выражение — единственный аргумент функции, вторые скобки не нужны: sum(x for x in ...). Подробно генераторы — в модуле «Итераторы и генераторы».
Своя область видимости
В Python 3 переменная цикла внутри включения не «утекает» наружу:
x = "снаружи"
squares = [x * x for x in range(3)]
print(x) # "снаружи" — включение не перезаписало x
Когда цикл лучше
Включения хороши для простых преобразований и фильтров. Пишите обычный цикл, если:
- логика сложная — несколько условий, промежуточные переменные, try/except;
- больше двух уровней вложенности;
- нужен побочный эффект (печать, запись в файл) — включение не для этого.
# плохо: включение ради побочного эффекта
[print(x) for x in items]
# хорошо
for x in items:
print(x)
Итог
[expr for x in it if cond]— список;{k: v for ...}— словарь;{expr for ...}— множество.ifпослеforфильтрует,a if c else bдоforпреобразует.- Несколько
for— в порядке вложенных циклов. (expr for ...)— ленивый генератор: экономит память, одноразовый.- Сложная логика — обычный цикл.
Практика решено 0 из 5
Одной строкой (через включение) создайте список evens_squared — квадраты чётных чисел от 1 до 20.
Какие тесты проверяют код (1)
assert evens_squared == [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
evens_squared = [x * x for x in range(1, 21) if x % 2 == 0]
Напишите функцию flatten(matrix), которая превращает список списков в плоский список
с помощью одного спискового включения с двумя for.
Какие тесты проверяют код (2)
assert flatten([[1, 2], [3], [], [4, 5]]) == [1, 2, 3, 4, 5] assert flatten([]) == []
def flatten(matrix):
return [x for row in matrix for x in row]
Напишите функцию price_with_tax(prices): на вход словарь «товар → цена», на выход —
новый словарь с ценами, увеличенными на 20% и округлёнными до 2 знаков,
только для товаров дороже 100. Используйте словарное включение.
Какие тесты проверяют код (2)
assert price_with_tax({"кофе": 200, "жвачка": 50, "чай": 150.5}) == {"кофе": 240.0, "чай": 180.6}
assert price_with_tax({}) == {}
def price_with_tax(prices):
return {name: round(p * 1.2, 2) for name, p in prices.items() if p > 100}
Что получится?
| [0, 1, 4] | {0, 1} | {0: 0, 1: 1} | генератор | ['чёт', 'нечет', 'чёт'] | |
|---|---|---|---|---|---|
[x * x for x in range(3)] |
|||||
{x % 2 for x in range(5)} |
|||||
{x: x for x in range(2)} |
|||||
(x for x in range(3)) |
|||||
['чёт' if x % 2 == 0 else 'нечет' for x in range(3)] |
Почему sum(x * x for x in range(10**7)) лучше, чем sum([x * x for x in range(10**7)])?
Войдите, чтобы отмечать пройденные уроки.