詳解Python直接賦值,深拷貝和淺拷貝
直接賦值: 對象的引用,也就是給對象起別名
淺拷貝: 拷貝父對象,但是不會拷貝對象的內(nèi)部的子對象。
深拷貝: 拷貝父對象. 以及其內(nèi)部的子對象
在之前的文章中,提到可變對象和不可變對象,接下來也是以這兩者的區(qū)別進行展開
直接賦值
對于可變對象和不可變對象,將一個變量直接賦值給另外一個變量,兩者 id 值一致,其實本質(zhì)上是將變量量綁定到對象的過程.
>>> a=1 >>> b=a >>> id(a) == id(b) True >>> c="string" >>> d=c >>> id(c) == id(d) True >>> e=[1,2,3] >>> f=e >>> id(e)==id(f) True
關于修改新變量的值,對原有變量會產(chǎn)生的影響,在可變對象和不可變對象 中也做了講述,這里通過幾個例子,重新溫習一下
不可變對象
>>> x=1 >>> y=x >>> id(x)==id(y) True >>> id(1)==id(y) True >>>>>> id(x) 1500143776 >>> y=y+1 >>> y 2 >>> x 1 >>> id(x)==id(y) False >>> id(y) 1500143808 >>> id(x) 1500143776
對于不可變對象,修改賦值后的新變量,不會對原有變量造成任何影響.為什么出現(xiàn)這種現(xiàn)象呢?因為不可變對象一旦創(chuàng)建之后就不允許被改變.后面對 y 進行的操作,其實是重新創(chuàng)建一個對象并綁定的結果:

可變對象
>>> m=[1,2,3] >>> n=m >>> id(n)==id(m) True >>> id(m) 1772066764488 >>> id(n[0]) 1772066764656 >>> n[0]=4 >>> n [4, 2, 3] >>> m [4, 2, 3] >>> id(n)==id(m) True >>> id(m) 1772066764488
對于可變對象,修改賦值后的變量,會對原有的變量造成影響,會導致其 value 值的改變,但是其id 值保持不變

從上圖不難看出,這個時候的 id(n[0]) 的值,和未修改前的 id值應該不一樣,可以輸出看一下
>>>id(n[0]) 1772066764752 # 最初沒有修改前是 1772066764656
n[0] 修改前后為什么 id 值出現(xiàn)改變呢? 首先需要明確一點 n[0] 綁定的是一個不可變對象,在文章的最初提到,不可變對象一旦創(chuàng)建就不允許修改.顯然對 n[0] 進行修改,不能在綁定對象的內(nèi)存上進行修改,那如何實現(xiàn)重新賦值呢?只能創(chuàng)建一個新的對象 4 ,然后將 n[0] 綁定到新的對象
淺拷貝和深拷貝
先看一下官方文檔的定義
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or
class instances).
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.
從文檔中不難看出,上面提到深拷貝和淺拷貝兩者區(qū)別在于在復合對象,那接下來也只討論復合對象.
淺拷貝
注意到官方文檔也提到對淺拷貝和深拷貝的定義,從上文中不難看出,淺拷貝構建一個復合對象,然后將原有復合對象包含的對象插入到新的復合對象中

從上圖不難看出,淺拷貝后,新復合對象包含的對象(可變或者不可變)的 id 值和原有對象包含的對象的 id 值相同
看一下具體例子:
>>> import copy >>> a=[1,2,[3,4]] >>> b=copy.copy(a) >>> id(b[0])==id(a[0]) True >>> id(b[2])==id(a[2]) True >>> id(b[2][0])==id(a[2][0]) True
現(xiàn)在讓我們試著修改一下淺拷貝后的 b 的值,在修改前,可以先思考一下,如果修改 b[0] 可能會發(fā)生什么?
由于 b[0] = 1,很顯然 1 屬于不可變對象,那么根據(jù)對不可變變量修改的規(guī)則,則 b[0] 會綁定到新的變量上,而 a[0] 的由于沒有修改,則保持不變,真的是這樣嗎?讓我們驗證一下
>>> b[0]=5 >>> b [5, 2, [3, 4]] >>> a [1, 2, [3, 4]]
接下來我們要嘗試修改一下 b[2],由于 b[2] 綁定的對象是 list,屬于可變對象,按照上面說的可變對象修改的規(guī)則,則修改后的 b[2] 的 id 值保持不變,但是其 value 值會發(fā)生改變. 同樣的讓我們通過例子驗證一下
>>> id(b[2]) 4300618568 >>> b[2][0]=6 >>> id(b[2]) 4300618568 >>> b [5, 2, [6, 4]] >>> a [1, 2, [6, 4]]
由于 b[2] 和 a[2] 綁定同一個可變對象,很顯然對 b[2] 的修改同樣會映射到 a[2] 上
深拷貝
深拷貝構建一個復合對象,然后遞歸的將原有復合包含的對象的副本插入到新的復合對象中

若上圖所示,深拷貝后,新的復合對象包含的對象,若對象為不可變對象,則 id 值保持不變,若對象為可變對象,則 id 值發(fā)生改變
看一個例子:
>>> import copy >>> a=[1,2,[3,4]] >>> b=copy.deepcopy(a) >>> id(b[0])==id(a[0]) True >>> id(b[2])==id(a[0]) False >>> id(b[2][0])==id(a[2][0]) True
接下來讓我們修改一下變量 b,這里就不在修改不可變對象 b[0] 和 b[1] 了,因為結果很明顯,對 a 不會產(chǎn)生任何影響,我們來修改 b[2],那么修改 b[2] 會對 a[2] 產(chǎn)生影響嗎?很明顯答案是不會,因為深拷貝就相當于克隆出了一個全新的個體,兩者不再有任何關系
>>> b[2][0]=5 >>> b [1, 2, [5, 4]] >>> a [1, 2, [3, 4]]
以上就是詳解Python直接賦值,深拷貝和淺拷貝的詳細內(nèi)容,更多關于Python直接賦值,深拷貝和淺拷貝的資料請關注腳本之家其它相關文章!
相關文章
Python爬蟲實現(xiàn)selenium處理iframe作用域問題
這篇文章主要介紹了Python爬蟲實現(xiàn)selenium處理iframe作用域問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01
狀態(tài)機的概念和在Python下使用狀態(tài)機的教程
這篇文章主要介紹了狀態(tài)機的概念和在Python下使用狀態(tài)機的教程,本文來自于IBM官方開發(fā)者技術文檔,需要的朋友可以參考下2015-04-04
python實現(xiàn)kNN算法識別手寫體數(shù)字的示例代碼
這篇文章主要介紹了python實現(xiàn)kNN算法識別手寫體數(shù)字的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08
Ruby使用eventmachine為HTTP服務器添加文件下載功能
這篇文章主要介紹了Ruby使用eventmachine為HTTP服務器添加文件下載功能的實例,同時作者也分享了Windows上eventmachine安裝報錯問題的解決方法,需要的朋友可以參考下2016-04-04
Python的加密模塊之hashlib 與 base64詳解及常用加密方法
我們來學習一下 Python 中的加密模塊,加密模塊在工作中被廣泛應用,比如數(shù)據(jù)的傳入 不希望被捕獲,通過把數(shù)據(jù)加密。這樣即使被捕獲也無法獲取到數(shù)據(jù)的真實信息,今天我們就來學習一下關于加密的方法,感興趣的朋友跟隨小編一起看看吧2023-02-02

