Развернутое объяснение
Итератор — это объект, который умеет возвращать элементы по одному при вызове встроенной функции next() и «знает», где он сейчас находится в последовательности.
Формально итератор реализует два метода:
метод
__iter__, возвращающий сам итератор;метод
__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:
При первом вызове
next()код выполняется до первогоyield, возвращает значение и «замораживает» состояние функции.Следующий
next()продолжает выполнение сразу послеyield, сохраняя локальные переменные.Когда функция доходит до конца или
return, выбрасываетсяStopIteration.
То есть генератор хранит своё состояние «внутри» функции, без явной реализации __next__ и __iter__.
Чем генератор отличается от обычного итератора?
Способ создания. Итератор чаще всего реализуется как класс определенными в нем методами
__iter__и__next__. Генератор же представляет собой функцию с операторомyieldили генераторное выражение((expr for ... in ...)).Удобство и объём кода. Итератор требует явного хранения состояния и явной реализации методов. Генератор автоматически запоминает состояние между yield: локальные переменные и позицию в коде.
Отношение между понятиями
Все генераторы — итераторы (поддерживают __next__ и __iter__).
Не все итераторы — генераторы (они могут быть реализованы обычными классами).
Память и ленивость
И генераторы, и итераторы обычно выдают значения по одному (лениво), что экономит память по сравнению со списками. Генераторы особенно удобны для больших или бесконечных последовательностей (чтение файла построчно, генерация событий). Проще говоря, генератор — это удобный способ написать итератор через функцию и yield.
Формулировка для собеседования
Итератор — это объект, у которого есть методы __iter__ и __next__, он возвращает элементы по одному и выбрасывает StopIteration, когда элементы заканчиваются. Генератор — это частный случай итератора: он создаётся функцией с yield и сам управляет своим состоянием между вызовами next(). Генераторы удобно использовать, когда нужно лениво генерировать последовательности без хранения всех данных в памяти.