python3:来自生成器的 list():生成项目更改列表时的奇怪行为
我有一个这样定义的生成器:
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 错误还是我错过了什么?
I have a generator defined like this:
def gen():
r = [0]
yield r
r[0] = 1
yield r
r[0] = 2
yield r
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.
Is this a python bug or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这不是一个错误,它完全按照你告诉它的方式去做。您多次生成同一个对象,因此您会获得对该对象的多个引用。在第一个代码片段中看不到三个
[2]
的唯一原因是 Python 不会及时返回并更改以前的输出以匹配对象发生突变的情况。尝试将显式调用next
时获得的值存储在变量中,并在最后检查它们 - 您将得到相同的结果。仅当迭代器再次前进后没有使用生成值时,这样的迭代器才有用。因此我通常会避免它,因为它在尝试预先计算部分或全部结果时会产生意想不到的结果(这也意味着它破坏了各种有用的技巧,例如 itertools.tee 和可迭代解包)。
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 callingnext
explicitly in variables and check them at the end - you'll get the same result.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).您想要:
这将产生三个列表,而不是一个列表三次。
You want:
That will yield three lists, not one list three times.