Короткий ответ
Итератор — объект, реализующий метод __next__(), который возвращает следующий элемент или поднимает StopIteration, когда элементы закончились; __iter__() должен возвращать сам итератор (обычно self).
Как это работает подробнее
Итерируемый объект (iterable) — то, у чего есть __iter__, возвращающий итератор; итератор хранит состояние (например, текущий индекс) и на каждый __next__ продвигает его, возвращая следующее значение, а при исчерпании поднимает StopIteration. Цикл for под капотом вызывает iter() один раз и затем next() до исключения.
Пример кода
example-241.py
class CountDown:
def __init__(self, start: int):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
cd = CountDown(3)
print(list(cd)) # [3, 2, 1]
print(list(cd)) # [] - итератор уже исчерпан, повторный обход ничего не даётЧто использовать на практике
- Практика. Итератор полезен, когда нужно отделить логику обхода от хранения коллекции или итерировать «на лету» без материализации всех элементов в памяти; состояние храните в атрибутах экземпляра, а не в глобальных переменных, чтобы несколько независимых обходов не мешали друг другу.
Подводные камни
- Риски. Путают iterable и iterator — пытаются вызвать
next()на списке напрямую (TypeError); забывают, что__iter__должен возвращать объект с__next__; ошибочно полагают, что повторныйforпо уже использованному итератору снова начнётся с начала.