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

发布于 2024-12-05 19:00:48 字数 586 浏览 2 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

江城子 2024-12-12 19:00:48

这不是一个错误,它完全按照你告诉它的方式去做。您多次生成同一个对象,因此您会获得对该对象的多个引用。在第一个代码片段中看不到三个 [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 calling next 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).

§对你不离不弃 2024-12-12 19:00:48

您想要:

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

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

You want:

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

That will yield three lists, not one list three times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文