Что такое генераторы и yield? Чем они отличаются от итераторов?

Итератор — это объект с методами __iter__ и __next__, который отдаёт элементы по одному и кидает StopIteration, когда данные закончились. Генератор — частный случай итератора: он создаётся функцией с yield или генераторным выражением и сам запоминает своё состояние между вызовами next(), не требуя отдельного класса.
Подробный ответ

Что такое итератор

Итератор — это объект, который возвращает элементы по одному при вызове next() и «знает», где он сейчас в последовательности.

Формально итератор реализует два метода:

  1. __iter__(), возвращающий сам итератор;

  2. __next__(), который возвращает очередное значение или выбрасывает StopIteration, когда значения закончились.

Пример простого итератора:

class CountDown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

for n in CountDown(3):
    print(n)  # 3, 2, 1

Класс явно хранит состояние и реализует протокол итератора.

Что такое генератор и yield

Генератор — это функция (или выражение), которая использует yield и при вызове возвращает объект‑генератор, то есть специальный итератор.

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

for n in countdown(3):
    print(n)  # 3, 2, 1

Особенности yield:

  1. При первом next() код выполняется до первого yield, возвращает значение и «замораживает» состояние функции.

  2. Следующий next() продолжает выполнение сразу после yield, сохраняя локальные переменные.

  3. Когда функция доходит до конца или до return, выбрасывается StopIteration.

То есть генератор хранит своё состояние внутри функции, без явной реализации __next__ и __iter__ вручную.

Чем генератор отличается от «обычного» итератора

  1. Способ создания. Обычный итератор чаще реализуют как класс с методами __iter__ и __next__. Генератор создаётся функцией с yield или генераторным выражением (expr for ... in ...).

  2. Объём кода. В генераторе не нужно самому хранить и обновлять состояние — всё делает интерпретатор. Код получается короче и проще.

Отношение между понятиями

Все генераторы — итераторы: у них есть __iter__ и __next__. Не все итераторы — генераторы: их можно писать классами без yield.

Память и ленивость

И генераторы, и итераторы обычно отдают значения по одному (лениво), не держа всю последовательность в памяти. Генераторы особенно удобны для больших/бесконечных последовательностей: чтение файла построчно, поток событий, последовательная обработка данных.

Фраза для собеседования

Итератор — это объект с __iter__ и __next__, который отдаёт элементы по одному и в конце бросает StopIteration. Генератор — это частный случай итератора, который создаётся функцией с yield и автоматически хранит своё состояние между вызовами next(). Генераторы позволяют писать итераторы в виде простой функции вместо отдельного класса.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге