2012-04-27 71 views
1

我剛剛開始編程,正在努力通過Python的「如何像計算機科學家一樣思考」。我在第9章參加練習之前一直沒有任何問題:克隆和深度拷貝之間的區別?

def add_column(matrix): 

    """ 
    >>> m = [[0, 0], [0, 0]] 
    >>> add_column(m) 
    [[0, 0, 0], [0, 0, 0]] 
    >>> n = [[3, 2], [5, 1], [4, 7]] 
    >>> add_column(n) 
    [[3, 2, 0], [5, 1, 0], [4, 7, 0]] 
    >>> n 
    [[3, 2], [5, 1], [4, 7]] 
    """ 

代碼應該使上面的doctest通過。我在最後一次測試中遇到困難:讓原始列表不受影響。我擡起頭的解決方案,這是以下情況:

x = len(matrix) 

matrix2 = [d[:] for d in matrix] 
for z in range(x): 
    matrix2[z] += [0] 
return matrix2 

我的問題是:爲什麼不能下聯是:

matrix2 = matrix[:] 

當這條線是代替原來的列表被編輯包括添加元素。 「如何成爲...」指南使其聽起來像克隆創建了一個新列表,可以在不影響原始列表的情況下對其進行編輯。如果那是真的,這裏發生了什麼?如果我使用:

matrix2 = copy.deepcopy(matrix) 

一切工作正常,但我並沒有印象,克隆會失敗下... 任何幫助將不勝感激!

回答

0

假設你有嵌套列表,複製將只複製對這些嵌套列表的引用。

>>> a = [1] 
>>> b = [2] 
>>> c = [a, b] 
>>> c 
[[1], [2]] 
>>> d = c[:] 
>>> d 
[[1], [2]] 
>>> d[1].append(2) 
>>> d 
[[1], [2, 2]] 
>>> c 
[[1], [2, 2]] 

As,其中,與copy.deepcopy()

>>> d = copy.deepcopy(c) 
>>> d[1].append(2) 
>>> c 
[[1], [2]] 
>>> d 
[[1], [2, 2]] 

這是任何可變項目真。 copy.deepcopy()將嘗試確保它們也被複制。

還值得注意的是,使用d = c[:]來複制列表不是一個非常明確的語法。更好的解決方案是d = list(c)list()從任何迭代中返回一個新列表,包括另一個列表)。顯然更明確的是copy.copy()

+0

感謝您的幫助 - 我想我在這一點上理解。是否有任何理由爲什麼要製作一個矩陣的離散副本,但保持嵌套列表引用同一個對象?我並沒有深入到這個過程中來預測這將是什麼,除了混淆之外...... – Alxmrg 2012-04-27 18:10:09

+0

這不是一個設計決定,更多的是對Python的工作方式的反響。無論何時使用Python進行賦值,您都不會複製該對象,只需將該變量指定爲引用即可。任意做別的事情都沒有意義。 – 2012-04-27 18:14:43

1

在你的情況下,matrix包含其他列表,所以當你做matrix[:],你克隆matrix,其中包含對其他列表的引用。那些也沒有被克隆。所以,當您編輯這些時,它們在原始matrix列表中仍然相同。但是,如果您將一個項目追加到副本(matrix[:]),它將不會被追加到原始列表中。

要想想象這一點,可以使用id函數,該函數返回每個對象的唯一編號:請參閱the docs

a = [[1,2], [3,4], 5] 
print 'id(a)', id(a) 
print '>>', [id(i) for i in a] 

not_deep = a[:] 
# Notice that the ids of a and not_deep are different, so it's not the same list 
print 'id(not_deep)', id(not_deep) 
# but the lists inside of it have the same id, because they were not cloned! 
print '>>', [id(i) for i in not_deep] 

# Just to prove that a and not_deep are two different lists 
not_deep.append([6, 7]) 
print 'a items:', len(a), 'not_deep items:', len(not_deep) 

import copy 
deep = copy.deepcopy(a) 
# Again, a different list 
print 'id(deep)', id(deep) 
# And this time also all the nested list (and all mutable objects too, not shown here) 
# Notice the different ids 
print '>>', [id(i) for i in deep] 

和輸出:

id(a) 36169160 
>> [36168904L, 35564872L, 31578344L] 
id(not_deep) 35651784 
>> [36168904L, 35564872L, 31578344L] 
a items: 3 not_deep items: 4 
id(deep) 36169864 
>> [36168776L, 36209544L, 31578344L] 
+0

我想我理解...所以如果「矩陣」不包括嵌套列表,我會沒事的,因爲只有一個級別克隆?這就是爲什麼深度複製的原理 - 它複製每一個層次,甚至是嵌套列表......我想「如何成爲...」是在嘗試更全面地理解最基本的概念之前,它最終使我困惑。謝謝! – Alxmrg 2012-04-27 18:08:10

+0

正確。 100%:D – jadkik94 2012-04-27 18:37:06