Generator
Определение#
Генератор — это специальный тип функции, которая возвращает итератор. Она позволяет возвращать значения по одному, не сохраняя всю последовательность в памяти целиком.
Зачем нужны#
Generators — идеальный выбор для работы с огромными наборами данных или бесконечными потоками. Они реализуют принцип lazy evaluation (ленивых вычислений): следующее значение вычисляется только тогда, когда оно действительно потребовалось. Это экономит мегабайты оперативной памяти, так как в ней всегда находится только один текущий элемент.
Как работает#
Вместо ключевого слова return в генераторах используется yield. Когда выполнение доходит до yield, функция возвращает значение и «замораживается», сохраняя все свои локальные переменные и текущую позицию. При следующем вызове (через функцию next() или в цикле for) она продолжает работу ровно с того места, где остановилась.
| Характеристика | Обычная функция | Генератор |
|---|---|---|
| Выход из функции | return (завершает работу) | yield (пауза и сохранение состояния) |
| Результат | Одно значение или список | Итератор (объект-генератор) |
| Память | Хранит всё сразу в RAM | Вычисляет элементы на ходу |
Основные методы#
| Метод | Что делает | Особенности |
|---|---|---|
__next__ |
Возвращает следующее значение. | Вызывается автоматически при использовании функции next(gen) или в цикле for. |
__send__ |
Отправляет значение в генератор. | value становится результатом текущего выражения yield внутри генератора. |
__throw__ |
Бросает исключение в месте паузы. | Позволяет генератору обработать ошибку или завершиться через try...except. |
__close__ |
Останавливает генератор. | Выбрасывает GeneratorExit внутри генератора, чтобы он мог корректно освободить ресурсы. |
Примеры#
# 1. Функция-генератор
def count_up_to(max_val):
count = 1
while count <= max_val:
yield count # Здесь функция ставится на паузу
count += 1
counter = count_up_to(3)
print(next(counter)) # 1
print(next(counter)) # 2
# 2. Генераторное выражение (Generator Expression)
# Работает как list comprehension, но в круглых скобках
squares_gen = (x**2 for x in range(1000000))
# В памяти только "инструкция", а не миллион чисел
print(next(squares_gen)) # 0
Ключевые мысли#
- Генераторы позволяют обрабатывать данные, которые не влезают в оперативную память.
- Состояние функции (локальные переменные) автоматически сохраняется между вызовами yield.
- После того как все значения возвращены, генератор выбрасывает исключение StopIteration, что позволяет циклам for корректно завершаться.