Как работает for в Python
Вопрос
Расскажите, что происходит под капотом цикла for и как сделать свой класс итерируемым.
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
`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 ошибок.
Термины по теме
Ещё по теме «Итераторы и генераторы»
- Когда выполняется тело генератора
- Разбить последовательность на пачки
- Рекурсивно развернуть вложенные списки
- Конвейер обработки лога на генераторах
- Свой итерируемый класс, который можно обходить много раз
- Когда выполняется finally в недочитанном генераторе
- Полезные функции itertools
- Ленивые вычисления