Python-copy()與deepcopy()區別

來源:互聯網
上載者:User

標籤:變數   嵌套   [1]   object   color   pre   code   http   為什麼   

http://blog.csdn.net/qq_32907349/article/details/52190796

 

學習過程中發現copy()和deepcopy()這對好基友實在是有點過分,搞的博主就有點傻傻分不清啊,但是呢本著一探到底的精神,還是要查資料搞清楚這對好基友的區別。

其實呢,copy()與deepcopy()之間的區分必須要涉及到python對於資料的儲存方式。

首先直接上結論:

—–我們尋常意義的複製就是深複製,即將被複製對象完全再複製一遍作為獨立的新個體單獨存在。所以改變原有被複製對象不會對已經複製出來的新對象產生影響。 
—–而淺複製並不會產生一個獨立的對象單獨存在,他只是將原有的資料區塊打上一個新標籤,所以當其中一個標籤被改變的時候,資料區塊就會發生變化,另一個標籤也會隨之改變。這就和我們尋常意義上的複製有所不同了。

對於簡單的 object,用 shallow copy 和 deep copy 沒區別

複雜的 object, 如 list 中套著 list 的情況,shallow copy 中的 子list,並未從原 object 真的「獨立」出來。也就是說,如果你改變原 object 的子 list 中的一個元素,你的 copy 就會跟著一起變。這跟我們直覺上對「複製」的理解不同。

看不懂文字沒關係我們來看代碼:

 
 1 >>> import copy 2 >>> origin = [1, 2, [3, 4]] 3 #origin 裡邊有三個元素:1, 2,[3, 4] 4 >>> cop1 = copy.copy(origin) 5 >>> cop2 = copy.deepcopy(origin) 6 >>> cop1 == cop2 7 True 8 >>> cop1 is cop2 9 False 10 #cop1 和 cop2 看上去相同,但已不再是同一個object11 >>> origin[2][0] = "hey!" 12 >>> origin13 [1, 2, [‘hey!‘, 4]]14 >>> cop115 [1, 2, [‘hey!‘, 4]]16 >>> cop217 [1, 2, [3, 4]]18 #把origin內的子list [3, 4] 改掉了一個元素,觀察 cop1 和 cop2

 

 

可以看到 cop1,也就是 shallow copy 跟著 origin 改變了。而 cop2 ,也就是 deep copy 並沒有變。

似乎 deep copy 更加符合我們對「複製」的直覺定義: 一旦複製出來了,就應該是獨立的了。如果我們想要的是一個字面意義的「copy」,那就直接用 deep_copy 即可。

那麼為什麼會有 shallow copy 這樣的「假」 copy 存在呢? 這就是有意思的地方了。

python的資料存放區方式

Python 儲存變數的方法跟其他 OOP 語言不同。它與其說是把值賦給變數,不如說是給變數建立了一個到具體值的 reference。

當在 Python 中 a = something 應該理解為給 something 貼上了一個標籤 a。當再賦值給 a 的時候,就好象把 a 這個標籤從原來的 something 上拿下來,貼到其他對象上,建立新的 reference。 這就解釋了一些 Python 中可能遇到的詭異情況:

 1 >> a = [1, 2, 3] 2 >>> b = a 3 >>> a = [4, 5, 6] //賦新的值給 a 4 >>> a 5 [4, 5, 6] 6 >>> b 7 [1, 2, 3] 8 # a 的值改變後,b 並沒有隨著 a 變 9 10 >>> a = [1, 2, 3]11 >>> b = a12 >>> a[0], a[1], a[2] = 4, 5, 6 //改變原來 list 中的元素13 >>> a14 [4, 5, 6]15 >>> b16 [4, 5, 6]17 # a 的值改變後,b 隨著 a 變了

 

上面兩段代碼中,a 的值都發生了變化。區別在於,第一段代碼中是直接賦給了 a 新的值(從 [1, 2, 3] 變為 [4, 5, 6]);而第二段則是把 list 中每個元素分別改變。

而對 b 的影響則是不同的,一個沒有讓 b 的值發生改變,另一個變了。怎麼用上邊的道理來解釋這個詭異的不同呢?

首次把 [1, 2, 3] 看成一個物品。a = [1, 2, 3] 就相當於給這個物品上貼上 a 這個標籤。而 b = a 就是給這個物品又貼上了一個 b 的標籤。 
 
第一種情況:

a = [4, 5, 6] 就相當於把 a 標籤從 [1 ,2, 3] 上撕下來,貼到了 [4, 5, 6] 上。

在這個過程中,[1, 2, 3] 這個物品並沒有消失。 b 自始至終都好好的貼在 [1, 2, 3] 上,既然這個 reference 也沒有改變過。 b 的值自然不變。

 
第二種情況:

a[0], a[1], a[2] = 4, 5, 6 則是直接改變了 [1, 2, 3] 這個物品本身。把它內部的每一部分都重新改裝了一下。內部改裝完畢後,[1, 2, 3] 本身變成了 [4, 5, 6]。

而在此過程當中,a 和 b 都沒有動,他們還貼在那個物品上。因此自然 a b 的值都變成了 [4, 5, 6]。

搞明白這個之後就要問了,對於一個複雜物件的淺copy,在copy的時候到底發生了什嗎? 
再看一段代碼:

>>> import copy>>> origin = [1, 2, [3, 4]]#origin 裡邊有三個元素:1, 2,[3, 4]>>> cop1 = copy.copy(origin)>>> cop2 = copy.deepcopy(origin)>>> cop1 == cop2True>>> cop1 is cop2False #cop1 和 cop2 看上去相同,但已不再是同一個object>>> origin[2][0] = "hey!" >>> origin[1, 2, [‘hey!‘, 4]]>>> cop1[1, 2, [‘hey!‘, 4]]>>> cop2[1, 2, [3, 4]]#把origin內的子list [3, 4] 改掉了一個元素,觀察 cop1 和 cop2

 

學過docker的人應該對鏡像這個概念不陌生,我們可以把鏡像的概念套用在copy上面。

概念圖如下: 

copy對於一個複雜物件的子物件並不會完全複製,什麼是複雜物件的子物件呢?就比如序列裡的嵌套序列,字典裡的嵌套序列等都是複雜物件的子物件。對於子物件,python會把它當作一個公用鏡像儲存起來,所有對他的複製都被當成一個引用,所以說當其中一個引用將鏡像改變了之後另一個引用使用鏡像的時候鏡像已經被改變了。

所以說看這裡的origin[2],也就是 [3, 4] 這個 list。根據 shallow copy 的定義,在 cop1[2] 指向的是同一個 list [3, 4]。那麼,如果這裡我們改變了這個 list,就會導致 origin 和 cop1 同時改變。這就是為什麼上邊 origin[2][0] = “hey!” 之後,cop1 也隨之變成了 [1, 2, [‘hey!’, 4]]。

而deepcopy概念圖如下: 

註:cop1 = copy.copy(origin)應為cop2 = copy.deepcopy(origin)

 

deepcopy的時候會將複雜物件的每一層複製一個單獨的個體出來。 
這時候的 origin[2] 和 cop2[2] 雖然值都等於 [3, 4],但已經不是同一個 list了。即我們尋常意義上的複製。

Python-copy()與deepcopy()區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.