關於python中深拷貝與淺拷貝問題

關於python中深拷貝與淺拷貝問題,做個研究小結。

《python核心編程》上說:

以存儲模型爲標準,類型可以分爲:

標量/原子類型 數值(所有的數值類型)、字符串(全部文字)

容器類型 列表、元組、字典

以更新模型爲標準,類型可以分爲:

可變類型:列表,字典

不可變類型:數字,字符串,元組

可變類型創建後允許值更新,不可變類型創建後不允許值更新。不可變類型創建新對象後若與舊對象重名,就會取代舊對象,比如:

x = 'Hello!'
id(x)
32074688
x = 'Hi'
id(x)
32014136
i = 0
id(i)
20069076
i = 1
id(i)
20069064

再深入研究就是深拷貝和淺拷貝。

淺拷貝是默認的拷貝類型,序列類型的可以通過三種方式實現淺拷貝:1、完全切片操作;2、利用工廠函數,比如list()等;3、使用copy模塊中的copy()函數。對於非容器類型沒有拷貝這一說。“對一個對象進行淺拷貝其實是新創建了一個類型跟原對象一樣,其內容是原來對象元素的引用,換句話說,這個拷貝的對象本身是新的,但是它的內容不是。”用一個例子作解釋:

a = [1,2,[3,4],5]
b = list(a)
id(a)
32082040
id(b)
32084416
[id(x) for x in a]
[20069064, 20069052, 32084576, 20069016]
[id(x) for x in b]
[20069064, 20069052, 32084576, 20069016]

可以看到b作爲淺拷貝創立的新對象,與a的地址不同(id()結果可以認爲是內存地址),但是其內容數據的地址卻是一致的,符合上述解釋。

再進一步分析:

a = [1,2,[3,4],5]
b = list(a)
a[0] = 100
a
[100, 2, [3, 4], 5]
b
[1, 2, [3, 4], 5]
b[0] = 'tt'
a
[100, 2, [3, 4], 5]
b
['tt', 2, [3, 4], 5]
a[2][0] = 30
a
[100, 2, [30, 4], 5]
b
['tt', 2, [30, 4], 5]
b[2][1] = 40
b
['tt', 2, [30, 40], 5]
a
[100, 2, [30, 40], 5]
可以看到淺拷貝後的b和原值a之間有某種聯繫。具體表現在其嵌套結構中數據似乎是引用關係,一個改變,另外一個也跟着改變,例如a[2][0]、b[2][1]更改之後的表現。所以有人說“淺拷貝只能做頂層複製,但是不能複製其嵌套的數據結構。”我覺得這個說法可以接受,至少目前自己找不到更好的解釋。

那麼如果不想複製數據後還存在這種相互引用關係該怎麼辦呢?用copy.deepcopy()方法。

import copy
a = [1,2,[3,4],5]
b = copy.deepcopy(a)
a[2][0] = 30
a
[1, 2, [30, 4], 5]
b
[1, 2, [3, 4], 5]
b[2][1] = 40
a
[1, 2, [30, 4], 5]
b
[1, 2, [3, 40], 5]

參考:http://www.cnblogs.com/wait123/archive/2011/10/10/2206580.html

    http://www.oschina.net/question/872916_84343


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章