python中copy()與deepcopy()的區(qū)別小結(jié)
前言
copy()與deepcopy()之間的區(qū)分必須要涉及到python對(duì)于數(shù)據(jù)的存儲(chǔ)方式。
深復(fù)制被復(fù)制對(duì)象完全再?gòu)?fù)制一遍作為獨(dú)立的新個(gè)體單獨(dú)存在。所以改變?cè)斜粡?fù)制對(duì)象不會(huì)對(duì)已經(jīng)復(fù)制出來(lái)的新對(duì)象產(chǎn)生影響。
淺復(fù)制并不會(huì)產(chǎn)生一個(gè)獨(dú)立的對(duì)象單獨(dú)存在,他只是將原有的數(shù)據(jù)塊打上一個(gè)新標(biāo)簽,所以當(dāng)其中一個(gè)標(biāo)簽被改變的時(shí)候,數(shù)據(jù)塊就會(huì)發(fā)生變化,另一個(gè)標(biāo)簽也會(huì)隨之改變。
import copy origin = [1, 2, [3, 4]] #origin 里邊有三個(gè)元素:1, 2,[3, 4] cop1 = copy.copy(origin) cop2 = copy.deepcopy(origin) cop1 == cop2 ------>True cop1 is cop2 ------>False #cop1 和 cop2 看上去相同,但已不再是同一個(gè)object origin[2][0] = "hey!" origin ------>[1, 2, ['hey!', 4]] cop1 ------>[1, 2, ['hey!', 4]] cop2 ------>[1, 2, [3, 4]]
可以看到 cop1,也就是 copy 跟著 origin 改變了。而 cop2 ,也就是 deep copy 并沒(méi)有變。
Python存儲(chǔ)方式
Python 存儲(chǔ)變量的方法跟其他 OOP 語(yǔ)言不同。它與其說(shuō)是把值賦給變量,不如說(shuō)是給變量建立了一個(gè)到具體值的 reference。
當(dāng)在 Python 中 a = something 應(yīng)該理解為給 something 貼上了一個(gè)標(biāo)簽 a。當(dāng)再賦值給 a 的時(shí)候,就好象把 a 這個(gè)標(biāo)簽從原來(lái)的 something 上拿下來(lái),貼到其他對(duì)象上,建立新的 reference。 這就解釋了一些 Python 中可能遇到的詭異情況:
>> a = [1, 2, 3] >>> b = a >>> a = [4, 5, 6] //賦新的值給 a >>> a [4, 5, 6] >>> b [1, 2, 3] # a 的值改變后,b 并沒(méi)有隨著 a 變 >>> a = [1, 2, 3] >>> b = a >>> a[0], a[1], a[2] = 4, 5, 6 //改變?cè)瓉?lái) list 中的元素 >>> a [4, 5, 6] >>> b [4, 5, 6] # a 的值改變后,b 隨著 a 變了
上面兩段代碼中,a 的值都發(fā)生了變化。區(qū)別在于,第一段代碼中是直接賦給了 a 新的值(從 [1, 2, 3] 變?yōu)?[4, 5, 6]);而第二段則是把 list 中每個(gè)元素分別改變。
而對(duì) b 的影響則是不同的,一個(gè)沒(méi)有讓 b 的值發(fā)生改變,另一個(gè)變了。怎么用上邊的道理來(lái)解釋這個(gè)詭異的不同呢?
首次把 [1, 2, 3] 看成一個(gè)物品。a = [1, 2, 3] 就相當(dāng)于給這個(gè)物品上貼上 a 這個(gè)標(biāo)簽。而 b = a 就是給這個(gè)物品又貼上了一個(gè) b 的標(biāo)簽。
第一種情況:
a = [4, 5, 6] 就相當(dāng)于把 a 標(biāo)簽從 [1 ,2, 3] 上撕下來(lái),貼到了 [4, 5, 6] 上。
在這個(gè)過(guò)程中,[1, 2, 3] 這個(gè)物品并沒(méi)有消失。 b 自始至終都好好的貼在 [1, 2, 3] 上,既然這個(gè) reference 也沒(méi)有改變過(guò)。 b 的值自然不變。
第二種情況:
a[0], a[1], a[2] = 4, 5, 6 則是直接改變了 [1, 2, 3] 這個(gè)物品本身。把它內(nèi)部的每一部分都重新改裝了一下。內(nèi)部改裝完畢后,[1, 2, 3] 本身變成了 [4, 5, 6]。
而在此過(guò)程當(dāng)中,a 和 b 都沒(méi)有動(dòng),他們還貼在那個(gè)物品上。因此自然 a b 的值都變成了 [4, 5, 6]。
搞明白這個(gè)之后就要問(wèn)了,對(duì)于一個(gè)復(fù)雜對(duì)象的淺copy,在copy的時(shí)候到底發(fā)生了什么?
再看一段代碼:
>>> import copy >>> origin = [1, 2, [3, 4]] #origin 里邊有三個(gè)元素:1, 2,[3, 4] >>> cop1 = copy.copy(origin) >>> cop2 = copy.deepcopy(origin) >>> cop1 == cop2 True >>> cop1 is cop2 False #cop1 和 cop2 看上去相同,但已不再是同一個(gè)object >>> origin[2][0] = "hey!" >>> origin [1, 2, ['hey!', 4]] >>> cop1 [1, 2, ['hey!', 4]] >>> cop2 [1, 2, [3, 4]] #把origin內(nèi)的子list [3, 4] 改掉了一個(gè)元素,觀(guān)察 cop1 和 cop2
學(xué)過(guò)docker的人應(yīng)該對(duì)鏡像這個(gè)概念不陌生,我們可以把鏡像的概念套用在copy上面。
概念圖如下:
copy對(duì)于一個(gè)復(fù)雜對(duì)象的子對(duì)象并不會(huì)完全復(fù)制,什么是復(fù)雜對(duì)象的子對(duì)象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是復(fù)雜對(duì)象的子對(duì)象。對(duì)于子對(duì)象,python會(huì)把它當(dāng)作一個(gè)公共鏡像存儲(chǔ)起來(lái),所有對(duì)他的復(fù)制都被當(dāng)成一個(gè)引用,所以說(shuō)當(dāng)其中一個(gè)引用將鏡像改變了之后另一個(gè)引用使用鏡像的時(shí)候鏡像已經(jīng)被改變了。
所以說(shuō)看這里的origin[2],也就是 [3, 4] 這個(gè) list。根據(jù) shallow copy 的定義,在 cop1[2] 指向的是同一個(gè) list [3, 4]。那么,如果這里我們改變了這個(gè) list,就會(huì)導(dǎo)致 origin 和 cop1 同時(shí)改變。這就是為什么上邊 origin[2][0] = “hey!” 之后,cop1 也隨之變成了 [1, 2, [‘hey!', 4]]。
而deepcopy概念圖如下:
deepcopy的時(shí)候會(huì)將復(fù)雜對(duì)象的每一層復(fù)制一個(gè)單獨(dú)的個(gè)體出來(lái)。
這時(shí)候的 origin[2] 和 cop2[2] 雖然值都等于 [3, 4],但已經(jīng)不是同一個(gè) list了。即我們尋常意義上的復(fù)制。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
python簡(jiǎn)單線(xiàn)程和協(xié)程學(xué)習(xí)心得(分享)
下面小編就為大家?guī)?lái)一篇python簡(jiǎn)單線(xiàn)程和協(xié)程學(xué)習(xí)心得(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Anaconda下Python中GDAL模塊的下載與安裝過(guò)程
這篇文章主要介紹了Anaconda下Python中GDAL模塊的下載與安裝方法,本文介紹在A(yíng)naconda環(huán)境下,安裝Python中柵格、矢量等地理數(shù)據(jù)處理庫(kù)GDAL的方法,需要的朋友可以參考下2023-04-04Tornado Web服務(wù)器多進(jìn)程啟動(dòng)的2個(gè)方法
這篇文章主要介紹了Tornado Web服務(wù)器多進(jìn)程啟動(dòng)的2個(gè)方法,Tornado是一個(gè)用Ptyhon寫(xiě)的WEB服務(wù)器,需要的朋友可以參考下2014-08-08Python OpenCV 圖像矯正的原理實(shí)現(xiàn)
這篇文章主要介紹了Python OpenCV 圖像矯正的原理實(shí)現(xiàn),檢測(cè)邊緣點(diǎn);以邊緣點(diǎn)作為輸入,采用Hough直線(xiàn)檢測(cè),檢測(cè)出最多點(diǎn)共線(xiàn)的四條直線(xiàn),更多相關(guān)內(nèi)容需要的朋友可以參考一下2022-07-07詳解python函數(shù)的閉包問(wèn)題(內(nèi)部函數(shù)與外部函數(shù)詳述)
這篇文章主要介紹了python函數(shù)的閉包問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Python使用內(nèi)置函數(shù)setattr設(shè)置對(duì)象的屬性值
這篇文章主要介紹了Python使用內(nèi)置函數(shù)setattr設(shè)置對(duì)象的屬性值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10TensorBoard 計(jì)算圖的可視化實(shí)現(xiàn)
今天小編就為大家分享一篇TensorBoard 計(jì)算圖的可視化實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02