← Назад к вопросам

Как происходит итерация генератора?

2.0 Middle🔥 231 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Итерация генератора в Python

Генератор — это функция, которая использует yield для возврата значений по одному. Это мощный инструмент для создания итеративных последовательностей с минимальным использованием памяти.

Как работает генератор

Когда ты вызываешь функцию-генератор, она не выполняется сразу. Вместо этого возвращается объект генератора:

def simple_generator():
    print("Начало")
    yield 1
    print("После первого yield")
    yield 2
    print("После второго yield")
    yield 3
    print("Конец")

# Генератор создан, но код не выполнен
gen = simple_generator()
print(type(gen))  # <class generator>

Итерация: step-by-step

Процесс итерации происходит через вызовы встроенной функции next():

# Первый вызов next()
value1 = next(gen)  # Выведет: "Начало", вернёт 1
print(value1)  # 1

# Второй вызов next()
value2 = next(gen)  # Выведет: "После первого yield", вернёт 2
print(value2)  # 2

# Третий вызов next()
value3 = next(gen)  # Выведет: "После второго yield", вернёт 3
print(value3)  # 3

# Четвёртый вызов next() — нет больше yield
try:
    next(gen)  # Выведет: "Конец"
except StopIteration:
    print("Генератор исчерпан")

Итерация с for loop (автоматическая)

Цикл for автоматически вызывает next() и ловит StopIteration:

for value in simple_generator():
    print(f"Получено: {value}")

# Эквивалентно:
gen = simple_generator()
while True:
    try:
        value = next(gen)
        print(f"Получено: {value}")
    except StopIteration:
        break

Протокол итератора

Генератор реализует протокол итератора:

class MyIterator:
    def __init__(self, max):
        self.max = max
        self.current = 0
    
    def __iter__(self):
        return self  # Возвращает себя
    
    def __next__(self):
        if self.current >= self.max:
            raise StopIteration
        self.current += 1
        return self.current

# Генератор — то же самое, но проще
def my_generator(max):
    current = 0
    while current < max:
        current += 1
        yield current

Практические примеры

1. Генератор чисел Фибоначчи

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

for num in fibonacci(10):
    print(num, end=" ")  # 0 1 1 2 3 5 8 13 21 34

2. Генератор чтения файла по строкам

def read_large_file(filepath):
    with open(filepath) as f:
        for line in f:
            yield line.rstrip("\n")

# Не загружает весь файл в память
for line in read_large_file("huge_file.txt"):
    process(line)

3. Двусторонний генератор (send)

def echo_generator():
    value = None
    while True:
        value = (yield value)  # Получить значение

gen = echo_generator()
next(gen)  # Инициализация (обязательно перед send)
print(gen.send("Hello"))  # Отправить значение → Hello
print(gen.send("World"))  # Отправить значение → World

Производительность: Генератор vs Список

# Список — загружает ВСЁ в память сразу
def number_list(n):
    result = []
    for i in range(n):
        result.append(i)
    return result

# Генератор — ленивые вычисления
def number_generator(n):
    for i in range(n):
        yield i

# Список использует O(n) памяти
list_result = number_list(1_000_000)  # ~40 MB

# Генератор использует O(1) памяти
gen_result = number_generator(1_000_000)  # ~100 bytes

Ключевые точки

  • Лень вычислений — значения вычисляются только при запросе
  • Состояние сохраняется — между yield сохраняются локальные переменные
  • StopIteration — исключение сигнализирует конец последовательности
  • Эффективность памяти — идеальны для больших наборов данных
  • Однократное использование — генератор можно итерировать только один раз