Вопрос проверяет, понимаете ли вы разделение ролей между “источником перебора” и “механизмом выдачи следующего элемента”.
__iter__() возвращает итератор — объект, из которого можно получать элементы по одному.__next__() возвращает следующий элемент из итератора.
Когда элементы закончились, __next__() должен выбросить StopIteration.
В for обычно сначала вызывается __iter__(), а затем много раз __next__().
Здесь важно понимать роли методов и то, кто кому что должен вернуть.
__iter__()— “дай итератор для обхода”.__next__()— “дай следующий элемент итератора”.
__iter__()
вызывается один раз на старт обхода
возвращает итератор
часто выглядит как return iter(self.data) или return self (если объект сам итератор)
__next__()
вызывается много раз
возвращает следующий элемент
в конце делает raise StopIteration
class Bag:
def __init__(self, items):
self._items = list(items)
def __iter__(self):
return iter(self._items) # отдаём итератор списка
Тут Bag — итерабельный, но не итератор.
class Counter:
def __init__(self):
self.n = 0
def __iter__(self):
return self # сам итератор
def __next__(self):
self.n += 1
return self.n
Так можно, но будьте аккуратны: состояние обхода хранится прямо в объекте.
Если __iter__() возвращает self, то повторный for по тому же объекту продолжит с текущего состояния, а не “сначала”.
Для “многоразовых” коллекций обычно возвращают новый независимый итератор.
__iter__() отвечает за получение итератора, а __next__() — за выдачу элементов и завершение перебора.