Урок 44 Генераторы

yield и ленивые вычисления

⏱ ~12 мин чтения· 📗 Средний

Что такое генератор?

Генератор — это функция, которая выдаёт значения по одному с помощью yield. В отличие от return, yield не завершает функцию, а приостанавливает её до следующего запроса. Это экономит память.

yield vs return

# Обычная функция (return)
def get_list():
    return [1, 2, 3]

# Функция-генератор (yield)
def get_generator():
    yield 1
    yield 2
    yield 3

print(get_list())         # [1, 2, 3] — сразу весь список в памяти
gen = get_generator()
print(next(gen))          # 1
print(next(gen))          # 2
print(next(gen))          # 3
# next(gen) → StopIteration

Генератор с бесконечной последовательностью

def infinite_counter():
    n = 0
    while True:
        yield n
        n += 1

counter = infinite_counter()
print(next(counter))  # 0
print(next(counter))  # 1
print(next(counter))  # 2
# Можно брать значения бесконечно без затрат памяти

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

# List comprehension (создаёт список в памяти)
squares_list = [x**2 for x in range(10)]          # список: 10 элементов
print(sum(squares_list))                          # 285

# Generator expression (круглые скобки, ленивое)
squares_gen = (x**2 for x in range(10))           # генератор: почти 0 памяти
print(sum(squares_gen))                           # 285

# Огромная разница при больших объёмах:
import sys
big_list = [x**2 for x in range(1_000_000)]       # ~8 МБ
big_gen = (x**2 for x in range(1_000_000))        # ~200 байт
print(sys.getsizeof(big_gen))                     # 200

Чтение большого файла построчно

def read_large_file(filepath):
    with open(filepath, "r", encoding="utf-8") as f:
        for line in f:
  yield line.strip()

for line in read_large_file("huge_log.txt"):
    if "ERROR" in line:
        print(line)  # обрабатываем строки по одной, а не весь файл сразу