__iter__
и __next__
, как итерируемый и итератор, это разные вещи. И хотя возможно иметь оба метода в одном классе, при __iter__
, возвращающем self
, это будет работать только для проверки концепций, а не для производственного кода.
Итерация будет иметь __iter__
метод, который возвращает объект с __next__
. Если оба экземпляра совпадают с
, то это просто демонстрация с ошибочным кодом
class Item:
def __init__(self, data):
self.data = data
def __iter__(self):
self.counter = 0
return self
def __next__(self):
self.counter += 1
if self.counter > len(self.data):
raise StopIteration()
return self.data[self.counter - 1]
Это будет работать - но если вы попытаетесь создать два независимых Итераторы одного и того же экземпляра Item не будут работать должным образом - поскольку оба будут использовать один и тот же счетчик - атрибут counter
в экземпляре.
Редко, однако, нужно реализовать __next__
: если __iter__
записано как функция генератора, имеющая yield
вместо возврата self
, это будет просто работать. Python вызовет __next__
на генераторе, созданном автоматически при каждом вызове __iter__
:
, это работает
class Item:
def __init__(self, data):
self.data = data
def __iter__(self):
for item in self.data:
yield item
Как видите, правильный путь является «бесполезным» и намного более простым, и в этом случае также может быть реализован путем возврата независимого итератора для данных. (Реализация yield необходима, если для получения каждого элемента требуются пользовательские вычисления)
это также работает
class Item:
def __init__(self, data):
self.data = data
def __iter__(self):
return iter(self.data)
(в этом случае Python вызовет __next__
на итераторе, созданном для self.data
)
Если вы действительно хотите реализовать __next__
, объект с этим методом должен отслеживать любые счетчики или указатели, необходимые для получения следующих элементов, и это должно быть независимо от экземпляра хоста. Самый простой способ сделать это - иметь второй класс, связанный с вашим первым, и вместо этого __iter__
вернуть его экземпляр:
рабочий "полный" пример
class Item:
def __init__(self, data):
self.data = data
def __iter__(self):
return ItemIterator(self)
class ItemIterator:
def __init__(self, item):
self.item = item
self.counter = 0
def __next__(self):
self.counter += 1
if self.counter > len(self.item.data):
raise StopIteration()
return self.item.data[self.counter - 1]