Короткий ответ
Итератор — это объект, который перебирает элементы коллекции по одному за раз и реализует протокол из методов __iter__() и __next__(). Когда элементы заканчиваются, __next__() выбрасывает StopIteration. Цикл for и функция next() как раз продвигают итератор по элементам.
Как это работает подробнее
Итерируемый объект и итератор выполняют разные роли: первый умеет только возвращать итератор, а второй реально осуществляет перебор.
- Протокол итерации. Объект считается итератором, если у него есть
__iter__(), возвращающий самого себя, и__next__(), отдающий следующий элемент или бросающийStopIterationв конце. - Итерируемые объекты. Списки, строки и словари итераторами не являются: функцию
iter(obj)используют, чтобы получить для них отдельный итератор. - Цикл for. Неявно вызывает
iter(), затем повторяетnext()и останавливается, когда ловитStopIteration.
Пример кода
Собственный итератор чётных чисел
class EvenNumbers:
def __init__(self, limit):
self.limit = limit
self.n = 2
def __iter__(self):
return self
def __next__(self):
if self.n > self.limit:
raise StopIteration
x = self.n
self.n += 2
return x
even = EvenNumbers(10)
print(list(even)) # [2, 4, 6, 8, 10]Что использовать на практике
- Обычный обход. Для перебора коллекций достаточно цикла
for— создавать итераторы вручную не нужно. - Собственная логика. Реализуй класс с
__iter__()и__next__(), когда последовательность нужно генерировать или обходить по особым правилам. - Явное управление.
iter()иnext()применяй там, где продвижение нужно контролировать руками.
Подводные камни
- Одноразовость. Исчерпавшись, итератор не перематывается: для повторного прохода нужен новый итератор.
- Только __next__(). Объекта с одним
__next__()мало для циклаfor— нужен и__iter__(), чтобы объект был итерируемым. - Гашение StopIteration. Не лови это исключение молча: оно сигнализирует о конце последовательности и должно обрабатываться по протоколу.
Как отвечать на собеседовании
- Определи итератор и назови оба метода протокола → поясни разницу между итерируемым объектом и итератором → приведи пример класса с
__next__()иStopIteration→ упомяни, что циклforнеявно использует этот протокол.