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

Python 从生成器创建迭代器将返回相同的对象,python,iterator,generator,Python,Iterator,Generator,假设我有一个大的数据列表,我想对它执行一些操作,我想让多个迭代器独立地执行这个操作 data = [1,2,3,4,5] generator = ((e, 2*e) for e in data) it1 = iter(generator) it2 = iter(generator) 我希望这些迭代器是不同的代码对象,但是it1是it2返回True。。。更令人困惑的是,以下生成器也是如此: # copied data gen = ((e, 2*e) for e in copy.deepcopy(

假设我有一个大的数据列表,我想对它执行一些操作,我想让多个迭代器独立地执行这个操作

data = [1,2,3,4,5]
generator = ((e, 2*e) for e in data)
it1 = iter(generator)
it2 = iter(generator)
我希望这些迭代器是不同的代码对象,但是
it1是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
。。。显然,发电机只是我想象中的一个更受约束的概念。

两个ITER都使用相同的发电机。调用
iter(thing)
返回该对象的
iter
(如果它有一个),因此,iter(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
或:

这两种解决方案都会产生以下效果:

next(it1)
(1, 2)
next(it2)
(1, 2)
生成器是迭代器。所有性能良好的迭代器都有一个
\uu iter\uuuu
方法,该方法应该

return self

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

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

iterator.\uuuu next\uuuu()
从容器返回下一项。如果有 如果没有其他项,则引发StopIteration异常。这种方法 对应于Python类型结构的tp_iternext插槽 Python/capi中的对象

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

>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> it2 = iter(it)
>>> next(it)
1
>>> next(it2)
2
>>> it is it2
True
因此,同样,列表是可编辑的,因为它有一个返回迭代器的
\uuuuuuuuuuuuuuuuuuuuuuuuuu
方法。这个迭代器还有一个
\uuuuuuuuuuuuuuuuu
方法,该方法应该总是返回自身,但它还有一个
\uuuuuuuuuuuuuuuuuuuuu
方法

因此,考虑一下:

>>> 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
然后使用:

it1 = paired(data)
it2 = paired(data)

在这种情况下,
it1
it2
将是两个独立的迭代器对象。

相关:
it1,it2=itertools.tee(generator)
“Once
tee()
已拆分,原始iterable不应在其他任何地方使用;否则,iterable可能会在未通知tee对象的情况下升级。此itertool可能需要大量辅助存储(取决于需要存储的临时数据量)。一般来说,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,则使用
list()
而不是
tee()
“更好:
g1,g2=((e,2*e)表示数据中的e),((e,2*e)表示数据中的e)
(但这仅在
数据
是一个序列时有效,它不能是迭代器。)你根本没有解决OP的误解。我们都知道(包括OP)这两个迭代器使用相同的生成器。OP想要知道的是为什么它会两次返回相同的迭代器。毕竟,如果对列表、字符串、集合或任何其他数据结构调用两次
iter
,将返回两个不同的迭代器。那么,为什么一个生成器不会发生这种情况呢?是的,我对生成器的理解是,它们描述了一种抽象的方式,一次一个地对数据序列执行转换,当对生成器调用
iter
时,返回了该抽象的一个具体实例。如果我正确理解了你的回答,那么生成器是一个更有限的概念,每个生成器只能有一个唯一的迭代器?我觉得生成器会返回iter方法,而不是自身的副本,所以我没有详细说明。在
javascript
中花费了太多时间,没有任何东西会返回自身的副本,除非这会使您的任务更加困难。@JacobThalman不,生成器是迭代器。它不返回自身的副本,因为它是一个迭代器,它的
\uuu iter\uuu
方法只返回
self
,正如迭代器协议所指定的那样。
>>> 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)