Перейти к содержанию
Educora
Продвинутый14 мин12 / 42

Генераторы списков и словарей

Создавай списки, словари и множества одной строкой: генераторы (comprehensions), условия-фильтры и выражения-генераторы.

Проверь себя
В этом уроке ты узнаешь
  • Заменять цикл генератором списка
  • Добавлять в генератор условие-фильтр и выражение if ... else
  • Писать генераторы словарей и множеств

В уроке о списках мы строили новый список так: создать пустой список, написать цикл, на каждом шаге вызвать append. Это три-четыре строки. В Python есть особая запись, которая делает то же самое одной строкой, — генератор (по-английски comprehension). Профессиональные программисты на Python пользуются им каждый день.

Генератор списка

В квадратных скобках сначала пишется выражение, которое вычисляется для каждого элемента, а затем обычная часть for. Оба способа дают одинаковый результат — сравни:

Python
squares = []
for n in range(1, 6):
    squares.append(n * n)
print(squares)

squares = [n * n for n in range(1, 6)]
print(squares)
▸ Ожидаемый результат
[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]
Text
[expression for item in iterable if condition]
{key: value for item in iterable if condition}
{expression for item in iterable}
Общий вид генераторов списка, словаря и множества; часть с if необязательна.

Главная сила генератора — фильтр: if в конце оставляет только элементы, подходящие под условие. А выражение может быть любым — вызов метода, функция, вычисление:

Python
numbers = [12, 7, 30, 5, 18, 21]
evens = [n for n in numbers if n % 2 == 0]
print(evens)

names = ['aysel', 'tural', 'ali']
print([name.title() for name in names])
print([len(name) for name in names])
▸ Ожидаемый результат
[12, 30, 18]
['Aysel', 'Tural', 'Ali']
[5, 5, 3]

Если элементы нужно не отбросить, а преобразовать двумя разными способами, используй условное выражение: A if условие else B. Обрати внимание: оно пишется перед for, а if-фильтр — после.

Python
numbers = [3, 8, 11, 14]
labels = ['even' if n % 2 == 0 else 'odd' for n in numbers]
print(labels)
▸ Ожидаемый результат
['odd', 'even', 'odd', 'even']

Генератор словаря

Если написать фигурные скобки и пару ключ: значение, получится словарь, а не список. Это очень удобно, чтобы построить словарь из списка, изменить значения или отфильтровать пары. В магазине началась скидка 10 %:

Python
names = ['Aysel', 'Tural', 'Ali']
lengths = {name: len(name) for name in names}
print(lengths)

prices = {'bread': 0.8, 'milk': 1.9, 'cheese': 6.5}
sale = {item: round(price * 0.9, 2) for item, price in prices.items()}
print(sale)

scores = {'Aysel': 91, 'Murad': 48, 'Leyla': 76}
passed = {name: s for name, s in scores.items() if s >= 50}
print(passed)
▸ Ожидаемый результат
{'Aysel': 5, 'Tural': 5, 'Ali': 3}
{'bread': 0.72, 'milk': 1.71, 'cheese': 5.85}
{'Aysel': 91, 'Leyla': 76}

Генераторы множеств и выражения-генераторы

Если в фигурных скобках записать одно выражение, получится множество — повторы удаляются автоматически. А если убрать скобки и передать генератор прямо в функцию, получится выражение-генератор: оно выдаёт элементы по одному, не создавая отдельный список, и экономит память.

Python
words = ['sun', 'moon', 'star', 'sky', 'planet']
lengths = {len(w) for w in words}
print(sorted(lengths))

total = sum(n * n for n in range(1, 11))
print(total)

table = [[1, 2, 3], [4, 5, 6]]
flat = [n for row in table for n in row]
print(flat)
▸ Ожидаемый результат
[3, 4, 6]
385
[1, 2, 3, 4, 5, 6]
В последнем примере две части for: внешняя перебирает строки таблицы, внутренняя — числа в каждой строке.

Выражения-генераторы особенно полезны с функциями any() и all(). any() возвращает True, если условию соответствует хотя бы один элемент, а all() — если все. Так можно одной строкой ответить на вопросы вроде «Кто-нибудь не сдал тест?» и «Все ли набрали больше 40 баллов?»

Python
scores = [72, 45, 88, 91]
print(any(s < 50 for s in scores))
print(all(s > 40 for s in scores))
print(max(len(w) for w in ['sun', 'planet', 'sky']))
▸ Ожидаемый результат
True
True
6
Пример: отчёт о температуре

Дневная температура в Баку за неделю: 24, 27, 31, 29, 33, 26, 30 °C. Найди, сколько дней было 30 °C и жарче, и переведи эти температуры в градусы Фаренгейта.

Показать решение
Жаркие дни отбираем фильтром: hot = [t for t in temps if t >= 30].
Их число даёт len(hot).
Каждую температуру переводим по формуле t * 9 / 5 + 32: [t * 9 / 5 + 32 for t in hot].
Результат — в коде ниже: 3 дня.
Python
temps = [24, 27, 31, 29, 33, 26, 30]
hot = [t for t in temps if t >= 30]
print('Hot days:', len(hot))
print([t * 9 / 5 + 32 for t in hot])
▸ Ожидаемый результат
Hot days: 3
[87.8, 91.4, 86.0]
Задание

С помощью генераторов списков построй и выведи два новых списка: 1) квадраты нечётных чисел из numbers, 2) слова из words длиннее 3 букв — заглавными буквами. Каждый список — генератор в одну строку.

Задание · Python
numbers = [4, 7, 10, 3, 8, 5]
words = ['sun', 'Baku', 'python', 'sea', 'tea', 'Caspian']
# 1) odd_squares: squares of the odd numbers
# 2) long_words: words longer than 3 letters, in capitals
# print both lists
▸ Ожидаемый результат
[49, 9, 25]
['BAKU', 'PYTHON', 'CASPIAN']
Задание

С помощью генератора словаря построй results: ключ — имя ученика, значение — 'pass', если балл не меньше 50, иначе 'fail'. Выведи его. Затем выведи сумму баллов сдавших с помощью выражения-генератора и sum().

Задание · Python
scores = {'Aysel': 91, 'Murad': 48, 'Leyla': 76, 'Elvin': 55}
# 1) results: name -> 'pass' or 'fail'
# 2) print results
# 3) print the sum of the scores that are at least 50
▸ Ожидаемый результат
{'Aysel': 'pass', 'Murad': 'fail', 'Leyla': 'pass', 'Elvin': 'pass'}
222

Главное

  • [выражение for x in последовательность] строит новый список одной строкой.
  • if в конце фильтрует элементы, а A if условие else B перед for преобразует их двумя способами.
  • {k: v for ...} создаёт словарь, а {x for ...} — множество.
  • Выражение-генератор вроде sum(x * x for x in ...) не создаёт отдельный список.
  • Если генератор становится сложным, вернись к обычному циклу.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Чему равно [n * 2 for n in range(3)]?