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

2024-04-19 00:37:52 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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也是递增的,这不是我想要的行为。你知道吗

这是怎么回事,有什么办法可以做我想做的吗?我在ubuntu14.04上使用python2.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。。。显然,发电机只是我想象中的一个更受约束的概念。你知道吗


Tags: 数据对象代码in列表fordatais
2条回答

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

return self

docs

The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:

iterator.__iter__()Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements. This method corresponds to the tp_iter slot of the type structure for Python objects in the Python/C API.

iterator.__next__() Return the next item from the container. If there are no further items, raise the StopIteration exception. This method corresponds to the tp_iternext slot of the type structure for Python objects in the 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

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

两个iter使用的是同一个生成器。调用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)

相关问题 更多 >