【问题标题】:python3: list() from generator: strange behaviour when yielding item-changed listspython3:来自生成器的列表():产生项目更改列表时的奇怪行为
【发布时间】:2011-11-22 03:36:07
【问题描述】:

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

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 错误还是我遗漏了什么?

【问题讨论】:

    标签: python python-3.x generator


    【解决方案1】:

    你想要:

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

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

    【讨论】:

      【解决方案2】:

      这不是一个错误,它完全按照您的指示去做。您多次生成相同的对象,因此您获得了对该对象的多次引用。您在第一个 sn-p 中没有看到三个 [2]s 的唯一原因是 Python 不会及时返回并更改先前的输出以匹配对象发生突变。尝试将在调用 next 时获得的值显式存储在变量中并在最后检查它们 - 你会得到相同的结果。

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

      【讨论】:

      • 请注意,如果生成器中的分配是针对整个列表对象而不是其元素进行的(例如r = [1] 而不是r[0] = 1),那么list(gen()) 将产生[[0], [1], [2]]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-23
      • 2014-12-13
      • 1970-01-01
      • 2021-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多