要說清楚Python中的深淺拷貝,需要搞清楚下面一系列概念:
變數-參考-物件(可變物件,不可變物件)-切片-拷貝(淺拷貝,深拷貝)
在Python中一切都是物件

甚至連type其本身都是物件,type物件
Python中變數與C/C++/Java中不同,它是指物件的參考,Python是動態型別,程式運行時候,會根據物件的型別來確認變數到底是什么型別,
單獨賦值:比如說:
>>> a = 3
在運行a=3后,變數a變成了物件3的一個參考,在內部,變數事實上是到物件記憶體空間的一個指標

因為Python的變數不過是物件的參考,或指向物件的指標,因此在程式中可以經常改變變數參考
代碼如下:
>>> x = 42 #變數系結到整型物件
>>> x = 'Hello' #現在又成了字串
>>> x = [1,2,3] #現在又成了串列
專業表述如下:
* 變數是一個系統表的元素,擁有指向物件的連接的空間
* 物件是被分配的一塊記憶體,存盤其所代表的值
* 參考是自動形成的從變數到物件的指標
* 特別注意: 型別屬于物件,不是變數
比如像剛才的a=3, 整數物件3包含了兩重資訊
1.值為3
2.一個頭部資訊:告訴Pthyon,這是個整數物件[相當于一個指向int的指標]
共享參考: 比如說:
代碼如下:
>>> a = 3
>>> b = a
在運行賦值陳述句b = a之后,變數a和變數b指向了同一個物件的記憶體空間.


從上圖可以看到,a和b,其id完全一樣,指向同一個整數物件3,或者說同一塊記憶體

如果刪掉a后, 不會影響b

拷貝概念的引入就是針對:可變物件的共享參考潛在的副作用而提出的.
【可變物件-不可變物件】
在Python中不可變物件指:一旦創建就不可修改的物件,包括字串,元祖,數字
在Python中可變物件是指:可以修改的物件,包括:串列、字典
上面說的a,b都是整數,整數是不可變物件,如果是可變物件的話,就是另外一回事了,
代碼如下:
>>> L1 = [2,3,4] #L1變數指向的是一個可變物件:串列
>>> L2 = L1 #將L1值賦給L2后,兩者共享參考同一個串列物件[1,2,3,4]
>>> L1[0] = 200 #因為串列可變,改變L1中第一個元素的值
>>> L1; L2 #改變后,L1,L2同時改變,因為物件本身值變了
[200, 3, 4]
[200, 3, 4]
如果不想改變串列L2的值,有兩種方法:切片 和 copy模塊
代碼如下:
>>> L1 = [2,3,4]
>>> L2 = L1
>>> id(L1);id(L2) #共享參考一個可變物件
45811784L
45811784L
>>> L2 = L1[:] #切片操作
>>> id(L1);id(L2) #切片后,物件就不一樣了
45811784L
45806920L
>>> L1[0] = 200
>>> L1;L2 #L1發生改變,L2沒有變化
[200, 3, 4]
[2, 3, 4]
【拷貝】
- 切片技術應用于所有的序列,包括:串列、字串、元祖
但切片不能應用于字典,對字典只能使用D.copy()方法或D.deepcopy()方法.

- 深淺拷貝,即可用于序列,也可用于字典
代碼如下:
>>> import copy
>>> X = copy.copy(Y) #淺拷貝:只拷貝頂級的物件,或者說:父級物件
>>> X = copy.deepcopy(Y) #深拷貝:拷貝所有物件,頂級物件及其嵌套物件,或者說:父級物件及其子物件
如果字典只有頂級物件:

如果字典中嵌套物件:

【結論】
深淺拷貝都是對源物件的復制,占用不同的記憶體空間
如果源物件只有一級目錄的話,源做任何改動,不影響深淺拷貝物件
如果源物件不止一級目錄的話,源做任何改動,都要影響淺拷貝,但不影響深拷貝
序列物件的切片其實是淺拷貝,即只拷貝頂級的物件
直接賦值:其實就是物件的參考(別名),
淺拷貝(copy):拷貝父物件,不會拷貝物件的內部的子物件,
深拷貝(deepcopy): copy 模塊的 deepcopy 方法,完全拷貝了父物件及其子物件,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/227230.html
標籤:Python
