2011-11-23 69 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代碼作爲操縱對象引用的方式來思考的話,你將會直觀地理解代碼是否可能最終引用了像這樣的多個地方的同一個對象,儘管可能總會有不明確的情況這讓你感到驚訝。

相關問題