В чём разница между итераторами и генераторами в Python?

«В чём разница между итераторами и генераторами в Python?» — вопрос из категории Python, который задают на 33% собеседований Data Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

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

Пример итератора (класс):

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

    def __iter__(self):
        return self

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

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

Пример генератора (функция с yield):

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

for num in count_down(3):
    print(num)  # 3, 2, 1

Ключевые отличия:

  1. Синтаксис: Генераторы проще и короче писать.
  2. Память: Генераторы не хранят всю последовательность в памяти, что критично для больших или бесконечных потоков данных.
  3. Состояние: Генератор автоматически сохраняет состояние выполнения между вызовами __next__(). После истощения (StopIteration) его нельзя переиспользовать.
  4. Использование: Любой генератор является итератором, но не наоборот.