Генераторы являются итераторами . Все итераторы с хорошим поведением имеют метод __iter__
, который должен просто
return self
Из документов
Сами объекты итератора должны поддерживать следующее
два метода, которые вместе образуют протокол итератора:
iterator.__iter__()
Возвращает сам объект итератора . Это
требуется, чтобы и контейнеры, и итераторы могли использоваться с
для и в заявлениях. Этот метод соответствует слоту tp_iter
структура типов для объектов Python в API Python / C.
iterator.__next__()
Вернуть следующий предмет из контейнера. Если там
больше нет предметов, вызовите исключение StopItate. Этот метод
соответствует слоту tp_iternext структуры типа для Python
объекты в API Python / C.
Итак, рассмотрим другой пример итератора:
>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> it2 = iter(it)
>>> next(it)
1
>>> next(it2)
2
>>> it is it2
True
Итак, опять же, список итерируемый , потому что он имеет __iter__
метод, который возвращает итератор . Этот итератор также имеет метод __iter__
, который должен всегда возвращать себя, но он также имеет метод __next__
.
Итак, рассмотрим:
>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> hasattr(x, '__iter__')
True
>>> hasattr(x, '__next__')
False
>>> hasattr(it, '__iter__')
True
>>> hasattr(it, '__next__')
True
>>> next(it)
1
>>> next(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
А для генератора:
>>> g = (x**2 for x in range(10))
>>> g
<generator object <genexpr> at 0x104104390>
>>> hasattr(g, '__iter__')
True
>>> hasattr(g, '__next__')
True
>>> next(g)
0
Теперь вы используете выражения генератора . Но вы можете просто использовать функцию генератора. Самый простой способ выполнить то, что вы делаете, это просто использовать:
def paired(data):
for e in data:
yield (e, 2*e)
Тогда используйте:
it1 = paired(data)
it2 = paired(data)
В этом случае it1
и it2
будут двумя отдельными объектами итератора.