当我复制并编辑此列表时到底发生了什么?

时间:2011-11-23 22:13:02

标签: python list python-3.x

我无法弄清楚为什么会发生这种情况:

A = [[1,0], [2,2]]
B = list(A)

print('start A:', A, 'start B:', B)
A[0][0] = 999
print('end A:', A, 'end B:', B)

返回:

start A: [[1, 0], [2, 2]] start B: [[1, 0], [2, 2]]
end A: [[999, 0], [2, 2]] end B: [[999, 0], [2, 2]]

列表A和B最终是相同的,即使我从A中明确地复制了B.这只发生在我做A [0] [0] = 999;如果我用A [0] = 999替换它,那么A和B在结尾处是不同的。

这背后的原因是什么,有没有办法以这种方式改变A而不影响B?

5 个答案:

答案 0 :(得分:3)

您正在创建原始列表的浅层副本,这是一个新列表,其中包含与原始列表相同对象的新引用。

修改新列表对象不会改变原始列表。修改新列表中的对象修改旧列表中的对象,因为它们是相同的。

要获得完全独立的列表,请使用copy.deepcopy()创建深层副本

答案 1 :(得分:2)

A和B都包含相同的两个列表。

您的代码大致相当于:

x = [1, 0]
y = [2, 2]

A = [x, y]
B = [x, y]

操作A[0][0] = 999实际上正在执行x[0] = 999。也就是说,它不会修改A本身,它会修改列表x的第一个元素。由于A和B都引用了x,因此两者都会看到变化。

答案 2 :(得分:1)

像你这样的简单复制操作是,它只复制一级深度的项目而不会递归到嵌套结构中。你需要

>>> import copy
>>> A = [[1,0], [2,2]]
>>> B = copy.deepcopy(A)
>>> print('start A:', A, 'start B:', B)
start A: [[1, 0], [2, 2]] start B: [[1, 0], [2, 2]]
>>> A[0][0] = 999
>>> print('end A:', A, 'end B:', B)
end A: [[999, 0], [2, 2]] end B: [[1, 0], [2, 2]]

答案 3 :(得分:1)

AB是计算机内同一块内存的两个不同名称。

AB是两个单独的列表对象,但A[0]B[0]是计算机内同一块内存的两个不同名称。请从解释器中尝试以下操作:

id(B)
id(A)
id(B[0])
id(A[0])

答案 4 :(得分:1)

Python代码将引用操作为对象

分配给变量只是绑定一个名称来引用一个对象。

列表由一堆对象引用组成。 list(A)找到A中引用的所有对象,并创建一个新列表,其中包含对所有相同对象的引用。因此,如果A是列表列表,list(A)会生成一个新列表,其中包含对A中相同列表的引用。因此,从A和新列表中可以看到更改任何子列表。

当您需要完整的“深层”副本时,

copy.deepcopy可以帮助您解决这个问题。

一旦你学会将Python代码视为操纵对象这样的对象的引用,你就会直观地理解代码何时可能最终引用来自多个这样的同一个对象,尽管可能总是存在一些模糊的情况。让你大吃一惊。