假设我要执行一些操作的数据列表很大,并且我希望有多个迭代器独立执行此操作。
data = [1,2,3,4,5]
generator = ((e, 2*e) for e in data)
it1 = iter(generator)
it2 = iter(generator)
我希望这些迭代器是不同的代码对象,但是it1 is it2
返回True
...更令人困惑的是,以下生成器也是如此:
# copied data
gen = ((e, 2*e) for e in copy.deepcopy(data))
# temp object
gen = ((e, 2*e) for e in [1,2,3,4,5])
这实际上意味着当我调用next(it1)
时,it2
也会增加,这不是我想要的行为。
这是怎么回事,有什么办法可以做我想做的事吗?我在Ubuntu 14.04上使用python 2.7。
编辑:
我也尝试了以下方法:
gen = (e for e in [1,2,3,4,5])
it = iter(gen)
next(it)
next(it)
for e in gen:
print e
哪些印刷品3 4 5
...显然,生成器只是我想象中的一个更受限制的概念。
答案 0 :(得分:4)
生成器是迭代器。所有行为良好的迭代器都有一个__iter__
方法,应该简单
return self
从docs
需要迭代器对象本身来支持以下内容 两种方法共同构成了迭代器协议:
iterator.__iter__()
返回迭代器对象本身。这是 允许容器和迭代器与 for和in语句。此方法对应于的tp_iter插槽 Python / C API中Python对象的类型结构。
iterator.__next__()
返回容器中的下一项。如果有 没有其他项目,请引发StopIteration异常。这个方法 对应于Python类型结构的tp_iternext插槽 Python / C API中的对象。
因此,请考虑迭代器的另一个示例:
>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> it2 = iter(it)
>>> next(it)
1
>>> next(it2)
2
>>> it is it2
True
因此,同样,列表是可迭代的,因为它具有一个返回 iterator 的__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
将是两个单独的迭代器对象。
答案 1 :(得分:2)
两个迭代器都使用相同的生成器。调用iter(thing)
会返回事物的iter
(如果有),因此iter(generator)会在您两次调用时都返回相同的事物。 https://docs.python.org/3/library/stdtypes.html#generator-types
data = [1,2,3,4,5]
generator = ((e, 2*e) for e in data)
it1 = iter(generator)
it2 = iter(generator)
type(it1)
generator
以下是获得唯一生成器的两种方法:
import itertools
data = [1,2,3,4,5]
generator = ((e, 2*e) for e in data)
it1, it2 = itertools.tee(generator)
type(it1)
itertools._tee
或:
data = [1,2,3,4,5]
it1 = ((e, 2*e) for e in data)
it2 = ((e, 2*e) for e in data)
type(it1)
generator
两个解决方案都会产生此结果:
next(it1)
(1, 2)
next(it2)
(1, 2)