# Генераторы и итераторы

> Итератор — объект, выдающий элементы по одному через протокол __iter__/__next__; генератор — функция с yield, которая лениво производит последовательность значений, не храня её целиком в памяти.

Источник: https://llmdocs.ru/wiki/generators-iterators/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Протокол итератора**: методы __iter__ и __next__, исключение StopIteration
- **Итераторы**: PEP 234 (Python 2.1)
- **Генераторы**: PEP 255 (Python 2.2, 2001)
- **Генераторные выражения**: PEP 289 (Python 2.4)
- **send и throw**: PEP 342 (Python 2.5)
- **yield from**: PEP 380 (Python 3.3)
- **Стандартная библиотека**: itertools
**Итератор** в [Python](https://llmdocs.ru/wiki/python.md) — объект, который выдаёт элементы последовательности по одному и помнит, где остановился. **Генератор** — самый удобный способ создать итератор: это функция с ключевым словом `yield`, которая при каждом обращении вычисляет и отдаёт следующее значение, а затем «засыпает» до следующего запроса. Генераторы работают **лениво**: значения появляются только тогда, когда нужны, и последовательность не хранится в памяти целиком.

На итераторах построен цикл `for`, распаковка, `zip`, `map`, `enumerate`, чтение файлов построчно и обработка потоков данных любого размера.

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

Объект **итерируемый** (*iterable*), если у него есть метод `__iter__`, возвращающий итератор. **Итератор** имеет метод `__next__`, который возвращает следующий элемент или выбрасывает `StopIteration`, когда элементы кончились.[2] Цикл `for x in data` разворачивается примерно так:

```python
it = iter(data)              # вызывает data.__iter__()
while True:
    try:
        x = next(it)         # вызывает it.__next__()
    except StopIteration:
        break
    ...                      # тело цикла
```

Списки, кортежи, строки, словари, множества, файлы — итерируемые объекты. Различие важно: список можно обойти сколько угодно раз, а итератор — только один, после чего он исчерпан.

## Генераторные функции

Генераторы появились в Python 2.2 (PEP 255, 2001).[1] Функция, содержащая `yield`, при вызове не выполняет тело, а возвращает объект-генератор. Каждый `next()` выполняет код до следующего `yield`:

```python
def read_records(path):
    with open(path, encoding="utf-8") as f:
        for line in f:                       # файл читается построчно
            line = line.strip()
            if line and not line.startswith("#"):
                yield line.split(",")

def countdown(n):
    while n > 0:
        yield n
        n -= 1

gen = countdown(3)
print(next(gen), next(gen), next(gen))      # 3 2 1
# следующий next(gen) выбросит StopIteration
```

`read_records` обработает файл на десятки гигабайт, держа в памяти одну строку. Без генератора пришлось бы писать класс с методами `__iter__` и `__next__` и вручную хранить состояние.

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

Генераторное выражение похоже на списковое включение, но в круглых скобках и вычисляется лениво (PEP 289):[6]

```python
squares_list = [x * x for x in range(10_000_000)]   # список: сотни мегабайт памяти сразу
squares_gen = (x * x for x in range(10_000_000))    # генератор: байты, значения по запросу
total = sum(x * x for x in range(10_000_000))       # скобки функции можно не дублировать
```

## Конвейеры обработки

Генераторы удобно соединять в цепочки, где каждый этап обрабатывает элементы по одному — как [конвейеры](https://llmdocs.ru/wiki/pipes-redirection.md) в Unix:

```python
import itertools

records = read_records("events.csv")
errors = (r for r in records if r[1] == "ERROR")
messages = (r[2] for r in errors)
for msg in itertools.islice(messages, 10):           # первые 10 ошибок; файл дальше не читается
    print(msg)
```

Модуль `itertools` содержит готовые строительные блоки: `islice` (срез итератора), `chain` (склейка), `groupby` (группировка подряд идущих), `batched` (пакеты по *n*, Python 3.12), `product` и `permutations` (комбинаторика), `count` и `cycle` (бесконечные последовательности).[5]

## Расширенные возможности

- **`yield from`** (PEP 380, Python 3.3) делегирует выдачу значений вложенному генератору или итерируемому объекту: `yield from walk(subdir)` в рекурсивном обходе дерева.[3]
- **`send()`, `throw()`, `close()`** (PEP 342) превращают генератор в сопрограмму, принимающую значения извне. Исторически на этом были построены первые асинхронные фреймворки, а затем и [asyncio](https://llmdocs.ru/wiki/asyncio.md); сегодня для асинхронности используют `async def` и `await`.
- **Асинхронные генераторы** (`async def` с `yield`) и `async for` — для потоков данных, приходящих по сети.
- **Генераторы как [контекстные менеджеры](https://llmdocs.ru/wiki/context-managers.md)** — декоратор `contextlib.contextmanager` превращает генератор с одним `yield` в менеджер для оператора `with`.

## Типичные ошибки

- **Повторное использование исчерпанного итератора.** Второй проход по генератору ничего не выдаст — нужно создать его заново или сохранить результат в список.
- **Ленивость скрывает ошибки.** Код генератора не выполняется до первого `next()`, поэтому исключение возникнет позже, чем ожидается, — например, когда файл уже закрыт.
- **`len()` и индексация** для генераторов недоступны: длину можно узнать только пройдя его целиком.
- **Ненужная ленивость.** Для маленьких коллекций, которые обходятся несколько раз, список проще и быстрее.

Подробнее о функциональном стиле с итераторами — в руководстве Functional Programming HOWTO.[4]

## См. также

- [Декораторы](https://llmdocs.ru/wiki/decorators.md)
- [Контекстные менеджеры](https://llmdocs.ru/wiki/context-managers.md)
- [asyncio](https://llmdocs.ru/wiki/asyncio.md)
- [Python](https://llmdocs.ru/wiki/python.md)
- [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md)

## Источники

1. [PEP 255 — Simple Generators](https://peps.python.org/pep-0255/)
2. [PEP 234 — Iterators](https://peps.python.org/pep-0234/)
3. [PEP 380 — Syntax for Delegating to a Subgenerator](https://peps.python.org/pep-0380/)
4. [Python — Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html)
5. [Python — itertools](https://docs.python.org/3/library/itertools.html)
6. [PEP 289 — Generator Expressions](https://peps.python.org/pep-0289/)
