这是我的代码:
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[:])
。但有人可以告诉我为什么吗?
答案 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)创建list
,a
引用此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)处只有浅拷贝。