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)
“Oncetee()
已拆分,原始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)