Уроки модуля (3/4)
Генераторное выражение
Выражение-генератор похоже на понимание списка, но с круглые вместо квадратных скобок. Разница существенная: он не создает список в памяти, а создает элементы по требованию, по одному.
gen = (n * n for n in range(1_000_000))
# istantaneo, memoria costante: nessun calcolo ancora fatto
list_comp = [n * n for n in range(1_000_000)]
# alloca 1M di int in memoriaЛень (ленивая оценка)
Генератор ничего не делает, пока кто-нибудь не запросит следующее значение:
gen = (n * n for n in range(5))
next(gen) # 0 (calcolato adesso)
next(gen) # 1
next(gen) # 4
# ... e così via, fino a StopIterationОн исчерпывается: после потребления всех элементов он становится пустым навсегда. Чтобы повторно использовать его, необходимо воссоздать его.
Когда его использовать
Когда вы передаете результаты функции, которая обрабатывает их последовательно:
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costantesum, any, all, max, min, "".join(...) принимают генераторы.
Если для внешней функции требуются только круглые скобки вызова, вы можете
опустить собственный генератор:
sum((n * n for n in range(10))) # OK
sum(n * n for n in range(10)) # IDENTICO, più leggibileany и all: короткое замыкание
any(...) и all(...) прекращают выполнение итерации, как только получат ответ.
С помощью генератора следующие элементы даже не вычисляются.
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums) # True (si ferma a 4)
all(n > 0 for n in nums) # True
all(n > 2 for n in nums) # False (si ferma a 1)Шаблон: ленивый конвейер
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
prime_dieci.append(r)
if len(prime_dieci) == 10:
breakНикакого промежуточного списка, даже при огромных входных данных.
Потребляющие генераторы с суммой, любой, все
Выражения-генераторы идеально подходят для прямой передачи в функции, использующие итерации, например sum(), any() или all(). В этом случае вы можете опустить внешние скобки выражения-генератора, просто написав:
squares_sum = sum(x**2 for x in range(10))Это сохраняет ваш код чистым и обеспечивает высокую эффективность использования памяти.
Попробуйте это
Вычислите сумму квадратов чисел от 1 до 100 (включительно), используя выражение-генератор внутри sum(). Назначьте его tot. Оцените «всего».
Показать подсказку
диапазон(1, 101) включает 100.
Решение доступно после 3 попыток
Обзор упражнения
Учитывая `words = ['ciao', 'mondo', 'PYTHON', 'java']`, используйте функцию Any() с выражением-генератором, чтобы проверить, является ли ХОЯТЬ одно слово прописными буквами (.isupper()). Присвойте результат переменной has_uppercase. Оцените `has_uppercase`.
Показать подсказку
Any(p.isupper() для p в словах)
Решение доступно после 3 попыток
Дополнительная задача
Use a generator expression passed directly to the `sum()` function to calculate the sum of the squares of all integers from 1 to 100 inclusive. Store the result in `total_sum` and evaluate it.
Показать подсказку
Напишите total_sum = sum(x**2 для x в диапазоне (1, 101)). Двойные скобки не нужны.
Решение доступно после 3 попыток