Sobes.tech
Назад к вопросам
Junior — Middle
51

Каким образом реализовать возможность перебора элементов объекта как этого объекта, чтобы он стал итерируемым в Python?

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Чтобы объект можно было перебирать в for, он должен поддерживать итерационный протокол Python. Обычно для этого реализуют метод __iter__, который возвращает итератор. Если нужен полный контроль над последовательным обходом, можно также реализовать __next__ в отдельном итераторе.

Определение:

Итерируемый объект — это объект, по которому можно пройтись циклом for, получить элементы через iter() или использовать в конструкциях, ожидающих последовательность. В Python объект считается итерируемым, если iter(obj) возвращает итератор, а итератор, в свою очередь, умеет выдавать элементы через __next__ до StopIteration.

На практике есть два основных варианта:

  1. Реализовать __iter__, который возвращает готовый итератор.
  2. Сделать сам объект итератором, если он хранит состояние обхода и реализует и __iter__, и __next__.

Пример использования:

class MyContainer:
    def __init__(self, items):
        self.items = items

    def __iter__(self):
        return iter(self.items)


obj = MyContainer([1, 2, 3])

for x in obj:
    print(x)

Если нужен собственный итератор:

class MyIterator:
    def __init__(self, items):
        self.items = items
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.items):
            raise StopIteration
        value = self.items[self.index]
        self.index += 1
        return value


class MyContainer:
    def __init__(self, items):
        self.items = items

    def __iter__(self):
        return MyIterator(self.items)

Пояснение кода:

В первом примере класс MyContainer не является итератором сам по себе, но становится итерируемым, потому что __iter__ возвращает итератор от внутреннего списка. Это самый простой и частый вариант, когда объект-обёртка делегирует обход встроенному типу.

Во втором примере MyIterator уже хранит состояние обхода: текущий индекс. Метод __iter__ возвращает self, а __next__ по одному выдаёт элементы и завершает обход через StopIteration. Класс MyContainer создаёт новый итератор при каждом вызове iter(obj) или for.

Ключевые моменты:

  • Для for в Python объект должен быть итерируемым, то есть поддерживать __iter__.
  • __iter__ должен возвращать итератор, а не просто список или другой произвольный объект.
  • Итератор обязан реализовать __next__ и завершать обход через StopIteration.
  • Если объект сам хранит позицию обхода, он может быть одновременно и итерируемым объектом и итератором.
  • Самый простой способ сделать объект итерируемым — делегировать __iter__ встроенному контейнеру или генератору.
  • Для повторного прохода по данным обычно лучше возвращать новый итератор, а не хранить одно общее состояние.