> Что должно присутствовать у объекта, чтобы он был итератором в Python (Python)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: Сбер

Стек: Python

> Пример ответа

Короткий ответ

Итератор в Python - это объект, который реализует протокол итератора: метод __next__(), возвращающий следующий элемент или бросающий StopIteration, и метод __iter__(), возвращающий сам объект. Наличие __iter__() делает итератор одновременно итерируемым объектом. Формально достаточно реализовать __next__(), но без __iter__() объект не будет работать в циклах for и других конструкциях, ожидающих итерируемый объект.

Подробное объяснение

Протокол итератора в Python состоит из двух методов:

  • __iter__(self) - возвращает сам итератор. Этот метод делает объект итерируемым, позволяя использовать его в for, sum(), list() и т.д.
  • __next__(self) - возвращает следующий элемент последовательности. Когда элементы закончились, метод должен бросить исключение StopIteration.

Важные нюансы:

  • Итератор - это одноразовый объект: после исчерпания он не может быть перезапущен. Повторный вызов iter() на итераторе вернёт тот же самый объект, а не новый.
  • Итератор отличается от итерируемого объекта: итерируемый объект (например, список) реализует только __iter__(), возвращая новый итератор при каждом вызове.
  • Встроенная функция iter() проверяет наличие __iter__(), а next() - наличие __next__().
  • Для проверки, является ли объект итератором, можно использовать isinstance(obj, collections.abc.Iterator) - этот ABC проверяет наличие обоих методов.
  • С версии Python 3.7 __next__ можно реализовать как __next__ = lambda self: ..., но это скорее антипаттерн.

На практике

В реальном коде итераторы редко реализуют вручную - чаще используют генераторы (функции с yield), которые автоматически создают итератор. Однако понимание протокола необходимо для:

  • Создания кастомных потоковых или ленивых последовательностей.
  • Реализации бесконечных последовательностей (например, генерация чисел Фибоначчи без ограничения).
  • Понимания работы zip, map, filter и других функций, возвращающих итераторы.
  • Написания собственных классов, которые должны работать в циклах.

Типичный паттерн - класс, который является одновременно итерируемым и итератором (реализует оба метода), но это допустимо только если объект одноразовый. Для многоразового использования нужно разделять: контейнер реализует __iter__, а отдельный класс - итератор.

Пример кода

PYTHON
class Countdown:
"""Итератор, который считает от n до 1."""
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
value = self.current
self.current -= 1
return value
# Использование
for num in Countdown(3):
print(num) # 3, 2, 1
# Проверка через ABC
from collections.abc import Iterator
print(isinstance(Countdown(3), Iterator)) # True
# Одноразовость
cd = Countdown(2)
print(list(cd)) # [2, 1]
print(list(cd)) # [] - итератор исчерпан

Как отвечать на собеседовании

Начните с формального определения: два метода, их сигнатуры и поведение. Затем покажите понимание различий между итератором и итерируемым объектом - это частый источник путаницы. Упомяните StopIteration как механизм завершения. Если спросят про генераторы, скажите, что они реализуют тот же протокол автоматически. Хорошо добавить пример из практики: когда вы реализовывали итератор вручную и почему генератор не подходил (например, нужен был объект с состоянием и дополнительными методами).

Что проверяет интервьюер

  • Понимание протокола итератора, а не заученное определение.
  • Умение различать итератор и итерируемый объект.
  • Знание поведения StopIteration и одноразовости итераторов.
  • Понимание, как работает цикл for под капотом: вызывает iter() и затем next() до StopIteration.
  • Осведомлённость о collections.abc.Iterator и встроенных функциях iter()/next().

Типичные ошибки

  • Утверждение, что достаточно только __next__() - без __iter__() объект не будет работать в for.
  • Путаница между __iter__ и __next__: иногда говорят, что __iter__ возвращает следующий элемент.
  • Забывают про StopIteration или бросают IndexError вместо него.
  • Не учитывают одноразовость: пытаются использовать один и тот же итератор дважды.
  • Считают, что генераторы - это не итераторы, хотя они реализуют тот же протокол.
  • Реализуют __next__ без изменения внутреннего состояния - получается бесконечный цикл.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью