Ответ вслух Middle Итераторы и генераторы обновлено

Как работает for в Python

Вопрос

Расскажите, что происходит под капотом цикла for и как сделать свой класс итерируемым.

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Образцовый ответ: «for x in obj сначала вызывает iter(obj), то есть obj.iter(), и получает итератор. Дальше в цикле вызывается next(it), а когда итератор бросает StopIteration, цикл завершается без ошибки.

Что должно прозвучать в ответе

  • `for` вызывает `iter()`, затем `next()` до `StopIteration`

  • Итерируемый: `__iter__`, итератор: `__iter__` и `__next__`

  • Итерируемый лучше делать отдельно от итератора, чтобы обходить многократно

  • Проще всего сделать `__iter__` генератором

  • Запасной протокол: `__getitem__` с индексами от 0

Что могут спросить следом

  • Почему файл можно обойти только один раз?
  • Чем плох класс, который сам себе итератор?

Разбор

Образцовый ответ: «for x in obj сначала вызывает iter(obj), то есть obj.__iter__(), и получает итератор. Дальше в цикле вызывается next(it), а когда итератор бросает StopIteration, цикл завершается без ошибки. Итератор это объект с __next__ и с __iter__, который возвращает его самого. Чтобы сделать свой класс итерируемым, достаточно определить __iter__, и самый короткий способ сделать его генератором: def __iter__(self): yield from self._items. Тогда каждый for получит новый независимый итератор. Если класс сам себе итератор и хранит позицию в self, его получится обойти только один раз, а вложенные циклы по нему сломаются. Так устроены файлы и map: они итераторы и одноразовые. Есть и старый запасной протокол: если нет __iter__, но есть __getitem__, Python будет вызывать его с 0, 1, 2 до IndexError».

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме