初學Python,和C++還是有許多不同。直接賦值、淺拷貝和深拷貝,這三種拷貝對象的操作之間還是有許多的區別。Python語言的版本為2.7,在Pycharm中進行實驗。
一、直接賦值
用下面的代碼來實驗:
1 origin = [1, "string", [1, 3, 5]] 2 Copy = origin 3 print Copy 4 print id(origin), id(Copy) 5 Copy[0] = 5 6 print origin, Copy 7 Copy[1] = "changed" 8 print origin, Copy 9 Copy[2][0] = 111 10 print origin, Copy 11 print id(origin), id(Copy)
運行的結果如下:
[1, 'string', [1, 3, 5]] 38994824 38994824 [5, 'string', [1, 3, 5]] [5, 'string', [1, 3, 5]] [5, 'changed', [1, 3, 5]] [5, 'changed', [1, 3, 5]] [5, 'changed', [111, 3, 5]] [5, 'changed', [111, 3, 5]] 38994824 38994824
可見,直接賦值的新變量完完全全就是一個原對象的引用,任何對復制對象的引用都會影響到原對象。
二、淺拷貝
用相同的代碼來測試,僅僅把拷貝方式改成了copy.copy():
1 import copy 2 origin = [1, "string", [1, 3, 5]] 3 Copy = copy.copy(origin) 4 print Copy 5 print id(origin), id(Copy) 6 Copy[0] = 5 7 print origin, Copy 8 Copy[1] = "changed" 9 print origin, Copy 10 Copy[2][0] = 111 11 print origin, Copy 12 print id(origin), id(Copy)
運行的結果如下:
[1, 'string', [1, 3, 5]] 39453768 39510280 [1, 'string', [1, 3, 5]] [5, 'string', [1, 3, 5]] [1, 'string', [1, 3, 5]] [5, 'changed', [1, 3, 5]] [1, 'string', [111, 3, 5]] [5, 'changed', [111, 3, 5]] 39453768 39510280
這次可以發現,兩個對象指向的內存並不相同,也就是說,淺拷貝的對象是一個新的對象。另外,可以發現,對新對象的元素進行替換並不會影響到原對象,而對子對象——列表的修改會影響到原對象。
三、深拷貝
同樣,只是把拷貝方式換成copy.deepcopy():
1 import copy 2 origin = [1, "string", [1, 3, 5]] 3 Copy = copy.deepcopy(origin) 4 print Copy 5 print id(origin), id(Copy) 6 Copy[0] = 5 7 print origin, Copy 8 Copy[1] = "changed" 9 print origin, Copy 10 Copy[2][0] = 111 11 print origin, Copy 12 print id(origin), id(Copy)
結果如下:
[1, 'string', [1, 3, 5]] 39978056 39994504 [1, 'string', [1, 3, 5]] [5, 'string', [1, 3, 5]] [1, 'string', [1, 3, 5]] [5, 'changed', [1, 3, 5]] [1, 'string', [1, 3, 5]] [5, 'changed', [111, 3, 5]] 39978056 39994504
同樣,兩個對象指向的內存位置並不相同,說明創建了新對象。此外,新對象的任何改動都不影響到原有的對象。
結論:
(1)直接賦值是一個完完全全的引用,對新變量的任何改動都會影響到原對象。
(2)淺拷貝創建了新的對象,但是只拷貝了序列的元素,對於元素也是一個序列的情況(即子對象),只復制了對這個序列的引用!
(3)深拷貝是完完全全的拷貝,把原對象完整地拷貝到了新對象中。