2011-11-23 77 views
4

我想不出在所有为什么发生这种情况:当我复制并编辑此列表时,究竟发生了什么?

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复制乙这只发生在我做类似A [0] [0] = 999;如果我用A [0] = 999替换它,那么A和B在结尾处是不同的。

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

回答

3

你正在创建原始列表的浅拷贝,它是一个包含相同的对象与原始名单新引用一个新的列表。

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

要获得完全单独的列表,请使用copy.deepcopy()创建深拷贝

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,两者都会看到变化。

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]] 
1

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

AB是两个独立的列表对象,但A[0]B[0]是的计算机内存中的同一块两个不同的名字。尝试从解释如下:

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

不,他们不是。它们是单独的列表对象。 –

+0

@SvenMarnach - 很棒! –

1

Python代码操纵引用对象

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

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

copy.deepcopy存在,以帮助您解决这个问题,当你需要一个完整的“深”副本。

一旦你学会将Python代码作为操纵对象引用的方式来思考的话,你将会直观地理解代码是否可能最终引用了像这样的多个地方的同一个对象,尽管可能总会有不明确的情况这让你感到惊讶。

相关问题