为什么我不能改变我在使用yield时迭代的列表

时间:2017-08-01 15:25:36

标签: python

我在这里有一些可重现的代码:

def test():
    a = [0, 1, 2, 3]
    for _ in range(len(a)):
        a.append(a.pop(0)) 
        for i in range(2,4):
            print(a)
            yield(i, a)

打印出来:

[1, 2, 3, 0]
[1, 2, 3, 0]
[2, 3, 0, 1]
[2, 3, 0, 1]
[3, 0, 1, 2]
[3, 0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3]

这是我的预期,但当我list(test())时,我得到了:

[(2, [0, 1, 2, 3]),
 (3, [0, 1, 2, 3]),
 (2, [0, 1, 2, 3]),
 (3, [0, 1, 2, 3]),
 (2, [0, 1, 2, 3]),
 (3, [0, 1, 2, 3]),
 (2, [0, 1, 2, 3]),
 (3, [0, 1, 2, 3])]

为什么会这样,我该怎么做才能解决它?

4 个答案:

答案 0 :(得分:3)

因为您现在始终返回(i,a) a参考到列表中。因此,您不断将引用返回到相同的列表。 print语句没有问题,因为它会立即打印a 的状态

您可以返回列表的副本,例如:

def test():
    a = [0, 1, 2, 3]
    for _ in range(len(a)):
        a.append(a.pop(0)) 
        for i in range(2,4):
            print(a)
            yield(i, list(a))

答案 1 :(得分:3)

每次都会产生相同的列表,因此调用者的列表只有一堆对该列表的引用,每次调用时都会更新。当您屈服时,您需要复制列表:

def test():
    a = [0, 1, 2, 3]
    for _ in range(len(a)):
        a.append(a.pop(0)) 
        for i in range(2,4):
            print(a)
            yield(i, a[:])

答案 2 :(得分:1)

显式更好隐式:

import copy
def test():
    a = [0, 1, 2, 3]
    for _ in range(len(a)):
        a.append(a.pop(0)) 
        for i in range(2,4):
            print(a)
            yield(i, copy.copy(a))

答案 3 :(得分:1)

您最终得到了一个元组列表,元组的第二个元素是相同的列表。您可能会注意到它们都等同于生成器生成的最后一个列表,而不是第一个列表;列表正在改变,但元组都引用了同一个。

为清楚起见,请尝试修改其中一个列表。例如,如果您运行l[0][1].append(4),则会获得

[(2, [0, 1, 2, 3, 4]),
 (3, [0, 1, 2, 3, 4]),
 (2, [0, 1, 2, 3, 4]),
 (3, [0, 1, 2, 3, 4]),
 (2, [0, 1, 2, 3, 4]),
 (3, [0, 1, 2, 3, 4]),
 (2, [0, 1, 2, 3, 4]),
 (3, [0, 1, 2, 3, 4])]

所有列表都附加了4个,因为只有一个列表。

如果要返回副本,有几种方法。您可以yield (i, a[:])(使用切片表示法获取副本),yield (i, list(a))(使用list构造函数获取副本)或yield (i, copy.copy(a))(使用copy }模块)。