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

Что такое итерабельный объект в Python и как правильно реализовать пользовательский итерируемый объект?

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

Ответ

История вопроса: Понятие итерируемости появилось в Python для унификации работы с коллекциями: списком, словарём, множеством и т.д. Любой объект, по которому можно пройтись с помощью цикла for, считается итерируемым. Это реализовано через определённые магические методы.

Проблема: Python требует определённых протоколов для корректной работы циклов и функций, связанных с последовательностями. Если пользователь неправильно реализует эти протоколы в своём классе, стандартные механизмы (for, list(), sum() и др.) не будут работать или будут вести себя неожиданно.

Решение: Итерируемым является любой объект, реализующий метод __iter__. Итератор — тот, у кого есть метод __next__ и __iter__, возвращающий self. Обычно объект, возвращаемый __iter__, является итератором, но не обязательно. Пример:

class MyRange: def __init__(self, start, end): self.start = start self.end = end def __iter__(self): self.current = self.start return self def __next__(self): if self.current < self.end: val = self.current self.current += 1 return val raise StopIteration for x in MyRange(1, 4): print(x) # 1, 2, 3

Ключевые особенности:

  • Итерабельность определяется наличием метода __iter__.
  • Итератор должен реализовывать и __next__, и __iter__ (возвращающий self).
  • Возвращение нового объекта в __iter__ эффективно реализуется, если требуется несколько независимых проходов по коллекции.

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

Обязателен ли метод next для любого итерируемого объекта?

Нет. Для итерируемого объекта необходим только __iter__, возвращающий итератор. __next__ реализует только сам итератор. Например, у list нет метода __next__, но он итерируемый: его __iter__ возвращает экземпляр итератора.

lst = [1, 2, 3] print(hasattr(lst, '__next__')) # False

Может ли объект быть итератором сам по себе?

Да, если реализует оба метода — и __iter__, и __next__.

Можно ли создать несколько итераторов с независимым состоянием для одной коллекции?

Да, если __iter__ возвращает каждый раз новый объект-итератор.

class MyList: def __init__(self, data): self.data = data def __iter__(self): return iter(self.data)

Типовые ошибки и анти-паттерны

  • Реализация только __next__ без __iter__ (или наоборот).
  • Запоминание состояния на уровне класса, а не экземпляра, что приводит к багам при повторных проходах.

Пример из жизни

Негативный кейс: Класс итератора хранит состояние (например, текущий индекс) на уровне класса, а не экземпляра, из-за чего параллельные обходы ломают друг друга. Плюсы:

  • Меньше памяти (только один индекс). Минусы:
  • Ошибки при одновременной итерации двумя циклами.

Положительный кейс: Каждый итератор хранит своё состояние в экземпляре, созданном в __iter__. Плюсы:

  • Корректная работа нескольких итераторов. Минусы:
  • Незначительно больше расход памяти.