Python 深拷貝與淺拷貝詳解


要說清楚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] 

【拷貝】

  1. 切片技術應用於所有的序列,包括:列表、字符串、元祖

    但切片不能應用於字典。對字典只能使用D.copy()方法或D.deepcopy()方法.

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

如果字典只有頂級對象:

如果字典中嵌套對象:

【結論】

深淺拷貝都是對源對象的復制,占用不同的內存空間
如果源對象只有一級目錄的話,源做任何改動,不影響深淺拷貝對象
如果源對象不止一級目錄的話,源做任何改動,都要影響淺拷貝,但不影響深拷貝
序列對象的切片其實是淺拷貝,即只拷貝頂級的對象
直接賦值:其實就是對象的引用(別名)。
淺拷貝(copy):拷貝父對象,不會拷貝對象的內部的子對象。
深拷貝(deepcopy): copy 模塊的 deepcopy 方法,完全拷貝了父對象及其子對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM