Перейти к основному содержимому
Модуль 6 · Урок 3 из 423/36 в курсе~10 min
Уроки модуля (3/4)

Генераторное выражение

Выражение-генератор похоже на понимание списка, но с круглые вместо квадратных скобок. Разница существенная: он не создает список в памяти, а создает элементы по требованию, по одному.

Python
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

Лень (ленивая оценка)

Генератор ничего не делает, пока кто-нибудь не запросит следующее значение:

Python
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

Он исчерпывается: после потребления всех элементов он становится пустым навсегда. Чтобы повторно использовать его, необходимо воссоздать его.

Когда его использовать

Когда вы передаете результаты функции, которая обрабатывает их последовательно:

Python
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costante

sum, any, all, max, min, "".join(...) принимают генераторы. Если для внешней функции требуются только круглые скобки вызова, вы можете опустить собственный генератор:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDENTICO, più leggibile

any и all: короткое замыкание

any(...) и all(...) прекращают выполнение итерации, как только получат ответ. С помощью генератора следующие элементы даже не вычисляются.

Python
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)

Шаблон: ленивый конвейер

Python
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(). В этом случае вы можете опустить внешние скобки выражения-генератора, просто написав:

Python
squares_sum = sum(x**2 for x in range(10))

Это сохраняет ваш код чистым и обеспечивает высокую эффективность использования памяти.

Попробуйте это

Упражнение#python.m6.l3.e1
Попыток: 0Загрузка…

Вычислите сумму квадратов чисел от 1 до 100 (включительно), используя выражение-генератор внутри sum(). Назначьте его tot. Оцените «всего».

Загрузка редактора…
Показать подсказку

диапазон(1, 101) включает 100.

Решение доступно после 3 попыток

Обзор упражнения

Упражнение#python.m6.l3.e2
Попыток: 0Загрузка…

Учитывая `words = ['ciao', 'mondo', 'PYTHON', 'java']`, используйте функцию Any() с выражением-генератором, чтобы проверить, является ли ХОЯТЬ одно слово прописными буквами (.isupper()). Присвойте результат переменной has_uppercase. Оцените `has_uppercase`.

Загрузка редактора…
Показать подсказку

Any(p.isupper() для p в словах)

Решение доступно после 3 попыток

Дополнительная задача

Упражнение#python.m6.l3.e3
Попыток: 0Загрузка…

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 попыток