ПрограммированиеPython Backend разработчик

Как работает цикл for-in в Python? Какая инфраструктура обеспечивается для поддержки этого механизма, и что происходит "под капотом", когда мы итерируемся по кастомному объекту?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Цикл for-in в Python реализуется через протокол итерации, основанный на двух специальных методах: __iter__() и __next__(). Когда цикл начинается, Python вызывает iter(obj) (ищет метод __iter__). Если возвращается объект-итератор, в котором определён __next__(), цикл начинает вызывать этот метод для получения каждого следующего элемента.

Если элемент выдан успешно — итерация продолжается. Когда выбрасывается исключение StopIteration, цикл завершает работу.

Пример собственного итератора:

class Counter: def __init__(self, low, high): self.current = low self.high = high def __iter__(self): return self def __next__(self): if self.current > self.high: raise StopIteration else: self.current += 1 return self.current - 1 for num in Counter(1, 3): print(num) # Выведет 1, 2, 3

Тонкость: Многие стандартные структуры Python реализуют протокол итератора; вы легко можете сделать свои объекты такими же.

Вопрос с подвохом.

Можно ли использовать цикл for-in с любым объектом Python? Чем итерируемый объект отличается от итератора?

Ответ: Нет, цикл for-in требует, чтобы объект был итерируемым, т.е. реализовывал метод __iter__(), который возвращает итератор (объект с методом __next__()). Сам итератор возвращает себя через __iter__(), а итерируемый объект — нет.

Пример:

lst = [1, 2, 3] iterator = iter(lst) print(hasattr(lst, '__iter__')) # True print(hasattr(iterator, '__next__')) # True (итератор) print(hasattr(lst, '__next__')) # False (не итератор)

Примеры реальных ошибок из-за незнания тонкостей темы.


История

Проект: Обработка больших файлов.

Проблема: В проекте пытались повторить проход по файловому объекту (итерацию по строкам файла) дважды без явного открытия нового файла — и на второй итерации не получили ни одной строки (указатель уже в конце файла!).


История

Проект: Интеграция своего класса коллекции с фреймворком.

Проблема: Класс реализовал только __getitem__, но не __iter__, и не был совместим с генераторами и стандартными циклами (for). Из-за этого ломались сторонние библиотеки, ожидавшие итератор.


История

Проект: Использование map/filter на кастомных коллекциях.

Проблема: Собственный класс списка не реализовал __iter__ и __next__, и оказался не совместим со многими стандартными функциями Python, что выявилось только после интеграционных тестов и потребовало значительной переработки.