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

Jac*_*man 4 python iterator generator

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

data = [1,2,3,4,5]
generator = ((e, 2*e) for e in data)
it1 = iter(generator)
it2 = iter(generator)
Run Code Online (Sandbox Code Playgroud)

我希望这些迭代器是不同的代码对象,但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])
Run Code Online (Sandbox Code Playgroud)

这意味着在实践中,当我调用 时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
Run Code Online (Sandbox Code Playgroud)

哪个打印3 4 5......显然生成器只是我想象的一个更受限制的概念。

jua*_*aga 5

生成器是迭代器。所有行为良好的迭代器都有一个__iter__方法,应该简单地

return self
Run Code Online (Sandbox Code Playgroud)

来自文档

迭代器对象本身需要支持以下两种方法,它们共同构成了迭代器协议:

iterator.__iter__() 返回迭代器对象本身。这是允许容器和迭代器与 for 和 in 语句一起使用所必需的。该方法对应于Python/C API中Python对象类型结构的tp_iter槽。

iterator.__next__()返回容器中的下一个项目。如果没有更多项目,则引发 StopIteration 异常。此方法对应于 Python/C API 中 Python 对象的类型结构的 tp_iternext 槽。

因此,考虑迭代器的另一个示例:

>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> it2 = iter(it)
>>> next(it)
1
>>> next(it2)
2
>>> it is it2
True
Run Code Online (Sandbox Code Playgroud)

所以,再说一遍,列表是可迭代的,因为它有一个__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
Run Code Online (Sandbox Code Playgroud)

对于发电机:

>>> 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
Run Code Online (Sandbox Code Playgroud)

现在,您正在使用生成器表达式。但你可以只使用生成器函数。完成您正在做的事情的最直接的方法就是使用:

def paired(data):
    for e in data:
        yield (e, 2*e)
Run Code Online (Sandbox Code Playgroud)

然后使用:

it1 = paired(data)
it2 = paired(data)
Run Code Online (Sandbox Code Playgroud)

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