Python:为什么追加到列表会产生相同的值

时间:2017-11-15 15:51:56

标签: python

这是我的代码:

a = []
res = []
for i in range(0, 3):
    a.append(i)
    res.append(a)
print(res)

结果是:

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

但我希望结果是:

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

我知道解决方案是使用浅拷贝:res.append(a[:])。但有人可以告诉我为什么吗?

4 个答案:

答案 0 :(得分:4)

您将相同的内容(a)附加到res三次,因此它会出现3次。您在每次调用a之间更改append内容的事实并不重要。如果对append的每次调用都获得了a副本,那么您将获得预期的结果。

答案 1 :(得分:2)

当你附加对象" a"时,python实际上会附加指向原始列表的指针" a"。在循环的下一次迭代中,您更改原始对象,因此该对象的所有指针都显示对象的最新状态。 您可以在每次迭代中添加打印列表以查看实际操作。 你想要的是创建一个" a"的副本,它将保持不变,并将副本附加到" res"。就像你说的那样,使用语法a [:]可以完成这项工作。

答案 2 :(得分:2)

当您将 a 追加到 res 数组时,您将附加一个指向 a 变量的指针。不是 a 变量的“值”。所以当你完成后, res 数组会有'value' - [a,a,a]。

当您进行浅层复制时,您将在循环的该阶段将 a 变量的“值”复制到 res 数组中,为您提供“值” - [[0],[0,1],[0,1,2]]。

答案 3 :(得分:1)

a = []                    # (1) list created here
res = []
for i in range(0, 3):
    a.append(i)           # (2) list modified here
    res.append(a)         # (3) res is modified here
print(res)

您的代码所说的是:

在(1)创建lista引用此list

在(2)中,您从(1)修改list,但列表本身仍保留在同一个内存位置,a仍然引用此列表。

在(3)中,您只需复制一个引用并将其添加到res,但a和(1)中的列表仍然无法更改。

最终结果是res在(1)处获得了对列表的引用的3个副本。

这是一个副作用:

a[1] = 42
print(res)

输出:

[[0, 42, 2], [0, 42, 2], [0, 42, 2]]

你说你知道这是你所追求的代码:

a = []
res = []
for i in range(0, 3):
    a.append(i)
    res.append(a[:])     # (4) new list created
print(res)

在(4)处创建一个新列表,其内容与a所引用的列表相同。 a未引用此新列表,而是res的其中一个元素引用了此新列表。

首先,这意味着res保留了对列表的引用,这就是为什么它们可以长时间挂起来打印。其次a仍然是指原始列表。

这是一个副作用:

a[1] = 42
print(res)

输出:

[0, 42, 2] [[0], [0, 1], [0, 1, 2]]

但是,如果您检查此代码,这不是故事的结尾:

a = []
res = []
for i in range(0, 3):
    a.append([i])        # (5) Create a new list with one element
    res.append(a[:])     # (6) Shallow copy as above
print(res)

a[1].append(42)
print(a, res)

输出:

[[[0]], [[0], [1]], [[0], [1], [2]]]
[[0], [1, 42], [2]] [[[0]], [[0], [1, 42]], [[0], [1, 42], [2]]]

这是因为在(6)处只有浅拷贝。