Каким образом реализовать возможность перебора элементов объекта как этого объекта, чтобы он стал итерируемым в Python?
Ответ от нейросети
sobes.tech AI
Что хотят услышать интервьюеры:
Чтобы объект можно было перебирать в for, он должен поддерживать итерационный протокол Python. Обычно для этого реализуют метод __iter__, который возвращает итератор. Если нужен полный контроль над последовательным обходом, можно также реализовать __next__ в отдельном итераторе.
Определение:
Итерируемый объект — это объект, по которому можно пройтись циклом for, получить элементы через iter() или использовать в конструкциях, ожидающих последовательность. В Python объект считается итерируемым, если iter(obj) возвращает итератор, а итератор, в свою очередь, умеет выдавать элементы через __next__ до StopIteration.
На практике есть два основных варианта:
- Реализовать
__iter__, который возвращает готовый итератор. - Сделать сам объект итератором, если он хранит состояние обхода и реализует и
__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__встроенному контейнеру или генератору. - Для повторного прохода по данным обычно лучше возвращать новый итератор, а не хранить одно общее состояние.