从生成器创建迭代器会返回相同的对象

时间:2018-08-25 19:47:18

标签: python iterator generator

假设我要执行一些操作的数据列表很大,并且我希望有多个迭代器独立执行此操作。

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 ...显然,生成器只是我想象中的一个更受限制的概念。

2 个答案:

答案 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)

在这种情况下,it1it2将是两个单独的迭代器对象。

答案 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)