淺拷貝和深拷貝詳解
官方文件:
- A shallow copy constructs a new compound object and then (to the extent possible) inserts the same objects into it that the original contains.
- A deep copy constructs a new compound object and then, recursively,inserts copies into it of the objects found in the original.
在python中,物件賦值實際上是物件的引用。
淺拷貝: 拷貝物件的值,但不拷貝物件內部元素的值,只拷貝內部元素的引用
>>> SL = {'name': 'SL', 'friend': ['A', 'B', 'C']} >>> YS = SL.copy()
檢視SL,YS的id值
>>> print id(SL), id(YS) 139783840481360 139783840476248
可以看出,兩者的id值是不同的,說明拷貝物件的值。
接下來檢視SL[‘name’],YS[‘name’] 以及 SL[‘friend’],YL[‘friend’]的id值。>>>
內部元素的id值分別對應相同,說明都是指向相同物件。
下面對SL作出修改,然後檢視SL和YS的狀態>>> SL['name'] = 'SS' >>> SL['friend'][0] = 'Z' >>> SL {'name': 'SS', 'friend'
SL[‘name’]指向字串(不可變物件),SL[‘friend’]指向是列表(可變物件)。
可以看出,在替換SL中的不可變物件時,YS不受影響,修改SL中的可變物件時,YS也會相應改變。
分析:
SL[‘name’],YS[‘name’]原本指向相同物件,由於SL[‘name’]指向的是不可變物件。所以當改變SL[‘name’]時,會建立一個新的字串物件,並使SL[‘name’]指向它,YS[‘name’]仍然指向原本物件。
SL[‘frined’],YS[‘friend’]指向相同物件(即列表),屬於可變物件。因而修改SL[‘friend’]時,不需要建立新物件,直接修改SL[‘friend’]指向的列表。檢視一下改變之後SL[‘name’],YS[‘name’]和SL[‘friend’],YS[‘friend’]的id值
>>> print id(SL['name']), id(YS['name']) 139783774899256 139783840488224 >>> print id(SL['friend']), id(YS['friend']) 139783840438608 139783840438608
前兩者的id值已經不同,後兩者的id值相同,由此可見,上述分析是正確的。
因此,淺拷貝會得到一個新的物件,但對於物件內部的元素,無論是可變物件還是不可變物件都只拷貝引用
深拷貝: 拷貝物件的值,拷貝不可變元素的引用,拷貝可變元素的值
>>> SL = {'name': 'SL', 'friend': ['A', 'B', 'C']} >>> YS = deepcopy(SL)
檢視SL,YS的id值
>>> print id(SL), id(YS) 139732549292672 139732549294912
兩者的id值不同,說明拷貝物件的值。接下來檢視SL[‘name’],YS[‘name’] 以及 SL[‘friend’],YL[‘friend’]的id值。
>>> print id(SL['name']), id(YS['name']) 139732549298976 139732549298976 >>> print id(SL['friend']), id(YS['friend']) 139732549249360 139732549249216
前兩者的id值相同,後兩者的id值不同。這裡也對SL作出修改,然後檢視SL和YS的值
>>> SL['name'] = 'SS' >>> SL['friend'][0] = 'Z' >>> SL {'name': 'SS', 'friend': ['Z', 'B', 'C']} >>> YS {'name': 'SL', 'friend': ['A', 'B', 'C']}
不管對SL作出怎麼的修改都不會影響到YS的值
分析:
修改SL[‘name’]時,同上
SL[‘frined’],YS[‘friend’]原本就指向不同物件,修改SL[‘friend’]時,明顯不會影響到YS的值。下面檢視一下改變之後SL[‘name’],YS[‘name’]和SL[‘friend’],YS[‘friend’]的id值
>>> print id(SL['name']), id(YS['name']) 139732549296616 139732549298976 >>> print id(SL['friend']), id(YS['friend']) 139732549249360 139732549249216
意料之中,仍然對應不相同
因此,深拷貝也會得到一個新的物件,對於物件的內部元素,拷貝不可變物件的引用,拷貝可變物件的值
總而言之,淺拷貝得到的副本,修改副本內部的可變物件時會影響到原始物件;深拷貝得到的副本 ,無論如何修改副本都不會影響到原始物件。
注:淺拷貝和深拷貝只有在關於複合物件(包含其它物件的物件,列表,類等)才有區別。對於不可變物件,沒有被拷貝的說法,即使用deepcopy,檢視id值也是一樣的。