- Заменять цикл генератором списка
- Добавлять в генератор условие-фильтр и выражение
if ... else - Писать генераторы словарей и множеств
В уроке о списках мы строили новый список так: создать пустой список, написать цикл, на каждом шаге вызвать append. Это три-четыре строки. В Python есть особая запись, которая делает то же самое одной строкой, — генератор (по-английски comprehension). Профессиональные программисты на Python пользуются им каждый день.
Генератор списка
В квадратных скобках сначала пишется выражение, которое вычисляется для каждого элемента, а затем обычная часть for. Оба способа дают одинаковый результат — сравни:
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]
[expression for item in iterable if condition]
{key: value for item in iterable if condition}
{expression for item in iterable}if необязательна.Главная сила генератора — фильтр: if в конце оставляет только элементы, подходящие под условие. А выражение может быть любым — вызов метода, функция, вычисление:
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-фильтр — после.
numbers = [3, 8, 11, 14]
labels = ['even' if n % 2 == 0 else 'odd' for n in numbers]
print(labels)▸ Ожидаемый результат
['odd', 'even', 'odd', 'even']
Генератор словаря
Если написать фигурные скобки и пару ключ: значение, получится словарь, а не список. Это очень удобно, чтобы построить словарь из списка, изменить значения или отфильтровать пары. В магазине началась скидка 10 %:
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}Генераторы множеств и выражения-генераторы
Если в фигурных скобках записать одно выражение, получится множество — повторы удаляются автоматически. А если убрать скобки и передать генератор прямо в функцию, получится выражение-генератор: оно выдаёт элементы по одному, не создавая отдельный список, и экономит память.
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 баллов?»
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 дня.
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 букв — заглавными буквами. Каждый список — генератор в одну строку.
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().
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.
[n * 2 for n in range(3)]?