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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (73)

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

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。

提问于
用户回答回答于

你正在为它们使用相同的发生器。如果它有一个,则调用iter(thing)返回该东西iter,因此,iter(生成器)在你调用它时都会返回相同的内容。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)
用户回答回答于

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

>>> x = [1, 2, 3, 4, 5]
>>> it = iter(x)
>>> it2 = iter(it)
>>> next(it)
1
>>> next(it2)
2
>>> it is it2
True

所以,同样,列表是可迭代的,因为它有一个__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将两个独立的迭代器对象。

扫码关注云+社区

领取腾讯云代金券