python3:来自生成器的list():产生项目更改列表时的奇怪行为

时间:2011-09-21 16:56:09

标签: python python-3.x generator

我有一个像这样定义的生成器:

def gen():
    r = [0]
    yield r
    r[0] = 1
    yield r
    r[0] = 2
    yield r

它将产生三个从0到2的一个元素的列表:

>>> a = gen()
>>> next(a)
[0]
>>> next(a)
[1]
>>> next(a)
[2]
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#313>", line 1, in <module>
    next(a)
StopIteration

现在,当我从发电机制作清单时,我得到了这个:

>>> list(gen())
[[2], [2], [2]]

也就是说,它似乎每次都产生最后一次计算的值。

这是一个python bug还是我错过了什么?

2 个答案:

答案 0 :(得分:2)

这不是一个错误,它完全按照你的要求去做。您将多次产生相同的对象,因此您可以获得对该对象的多个引用。您在第一个片段中看不到三个[2]的唯一原因是Python不会及时返回并更改先前的输出以匹配对象发生变化时的情况。尝试存储在变量中明确调用next时获得的值,并在最后检查它们 - 您将得到相同的结果。

这样的迭代器仅在迭代器再次前进后没有使用生成值时才有用。因此,我通常会避免使用它,因为它在尝试预先计算某些或所有结果时会产生意外结果(这也意味着它会破坏各种有用的技巧,例如itertools.tee和可迭代的解包)。

答案 1 :(得分:0)

你想:

def gen():
    for i in (0,1,2):
        yield [i]

这将产生三个列表,而不是三个列表。