问题描述
我有一个这样定义的生成器:
I have a generator defined like this:
def gen():
r = [0]
yield r
r[0] = 1
yield r
r[0] = 2
yield r
它将产生一个元素的三个列表,从0到2:
it will yield three lists of one element going from 0 to 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
现在,当我从生成器中列出清单时,我得到了:
Now, when I go to make a list from the generator, I got this:
>>> list(gen())
[[2], [2], [2]]
也就是说,它似乎每次都会产生最后一个计算值.
That is, it seems to yield each time the very last computed value.
这是python的错误还是我缺少了什么?
Is this a python bug or am I missing something?
推荐答案
这不是bug,它确实按照您的指示执行.您会多次产生相同的对象,因此会获得对该对象的多个引用.您在第一个代码片段中看不到三个[2]
的唯一原因是Python不会及时返回并更改先前的输出以使对象发生突变时匹配.尝试存储在变量中显式调用next
时获得的值,并在最后检查它们-您将获得相同的结果.
It's not a bug, it does exactly what you told it to do. You're yielding the very same object several times, so you get several references to that object. The only reason you don't see three [2]
s in your first snippet is that Python won't go back in time and change previous output to match when objects are mutated. Try storing the values you get when calling next
explicitly in variables and check them at the end - you'll get the same result.
这种迭代器仅在下一次迭代该迭代器之后不使用任何产生值的情况下才有用.因此,我通常会避免使用它,因为在尝试预先计算部分或全部结果时会产生意外的结果(这也意味着它打破了各种有用的技巧,例如itertools.tee
和可迭代的拆包).
Such an iterator is only useful if no yielded value is used after the iterator is advanced another time. Therefore I'd generally avoid it, as it produces unexpected results when trying to pre-compute some or all results (this also means it breaks various useful tricks such as itertools.tee
and iterable unpacking).
这篇关于生成器的python3:list():产生项目更改列表时的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!