Как ответить
Главное различие — в способе создания и поведения: итератор — это объект, реализующий протокол итерации (методы __iter__ и __next__), а генератор — это частный случай итератора, который создаётся с помощью функции с yield или генераторного выражения. По сути, любой генератор — итератор, но не наоборот.
На практике разница проявляется в удобстве и состоянии. Итератор требует явного класса с методами, где нужно вручную управлять состоянием (например, индексом). Генератор делает то же самое «из коробки»: при каждом вызове yield он запоминает локальные переменные и точку остановки, а при следующем next() продолжает оттуда.
Вот как выглядит реализация простого итератора для последовательности чисел:
class Counter:
def __init__(self, limit):
self.limit = limit
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current >= self.limit:
raise StopIteration
self.current += 1
return self.current - 1
То же самое через генератор:
def counter(limit):
n = 0
while n < limit:
yield n
n += 1
Генератор короче, а поведение идентичное. Ещё одно отличие: генератор создаётся вызовом функции, и это ленивый объект, который не хранит все значения в памяти. Итератор тоже может быть ленивым (как в примере выше), но генератор — это рекомендуемый способ, потому что писать меньше кода и меньше шансов ошибиться с состоянием.
Также стоит упомянуть типы: итераторы — это любые объекты с протоколом. Например, list — итерируемый объект, но не итератор (у него есть __iter__, который возвращает итератор). Встроенные функции iter() и next() работают с обоими. Генераторы — это итераторы, которые дополнительно поддерживают send(), throw(), close() для сопрограмм.
На собеседовании я обычно упоминаю, что генераторы удобны для бесконечных последовательностей и потоковой обработки (например, чтение файла построчно). Итераторы в чистом виде встречаются реже — только когда нужно переопределить итерацию для сложного класса или сделать одноразовый проход.