Python中的賦值、淺拷貝、深拷貝介紹

來源:互聯網
上載者:User
和很多語言一樣,Python中也分為簡單賦值、淺拷貝、深拷貝這幾種“拷貝”方式。

在學習過程中,一開始對淺拷貝理解很模糊。不過經過一系列的實驗後,我發現對這三者的概念有了進一步的瞭解。

一、賦值

賦值算是這三種操作中最常見的了,我們通過一些例子來分析下賦值操作:

str例

代碼如下:


>>> a = 'hello'
>>> b = 'hello'
>>> c = a
>>> [id(x) for x in a,b,c]
[4404120000, 4404120000, 4404120000]


由以上指令中,我們可以發現a, b, c三者的地址是一樣的。所以以上賦值的操作就相當於c = a = b = 'hello'。

賦值是系統先給一個變數或者對象(這裡是'hello')分配了記憶體,然後再將地址賦給a, b, c。所以它們的地址是相同的。

list例

代碼如下:


>>> a = ['hello']
>>> b = ['hello']
>>> c = a
>>> [id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]


但是這種情況卻不一樣了,a和b的地址不同。為何?

因為str是不可變的,所以同樣是'hello'只有一個地址,但是list是可變的,所以必須分配兩個地址。

這時,我們希望探究以上兩種情況如果 修改值 會如何?

str例

代碼如下:


>>> a = 'world'
>>> [id(x) for x in a,b,c]
[4404120432, 4404120000, 4404120000]
>>> print a, b, c
world hello hello


這時a的地址和值變了,但是b, c地址和值都未變。因為str的不可變性,a要重新賦值則需重新開闢記憶體空間,所以a的值改變,a指向的地址改變。b, c由於'hello'的不變性,不會發生改變。

list例

代碼如下:


>>> a[0] = 'world'
>>> [id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]
>>> print a, b, c
['world'] ['hello'] ['world']


這時a, c的值和地址均改變,但二者仍相同,b不改變。由於list的可變性,所以修改list的值不需要另外開闢空間,只需修改原地址的值。所以a, c均改變。

在瞭解了以上的不同點之後,我們就能很好地分析淺拷貝和深拷貝了。

我們均用list作為例子。

二、淺拷貝

代碼如下:


>>> a = ['hello', [123, 234]]
>>> b = a[:]
>>> [id(x) for x in a,b]
[4496003656, 4496066752]
>>> [id(x) for x in a]
[4496091584, 4495947536]
>>> [id(x) for x in b]
[4496091584, 4495947536]


Line3,4可以看出a, b地址不同,這符合list是可變的,應開闢不同空間。那淺拷貝就是拷貝了一個副本嗎?再看Line5 - 8,我們發現a, b中元素的地址是相同的。如果說字串'hello'地址一致還能理解,但是第二個元素是list地址仍一致。 這就說明了淺拷貝的特點,只是將容器內的元素的地址複製了一份 。

接著我們嘗試修改a, b中的值:

代碼如下:


>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234, 345]]


a中第一個元素str改變,但是b中未改變;a中第二個元素改變,b中也改變。這就符合不可變的對象修改會開闢新的空間,可變的對象修改不會開闢新空間。也進一步證明了 淺拷貝僅僅是複製了容器中元素的地址 。

三、深拷貝

代碼如下:


>>> from copy import deepcopy
>>> a = ['hello', [123, 234]]
>>> b = deepcopy(a)
>>> [id(x) for x in a, b]
[4496066824, 4496066680]
>>> [id(x) for x in a]
[4496091584, 4496067040]
>>> [id(x) for x in b]
[4496091584, 4496371792]


深拷貝後,可以發現a, b地址以及a, b中元素地址均不同。這才是完全 拷貝了一個副本 。

修改a的值後:

代碼如下:


>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234]]


從Line4,5中可以發現僅僅a修改了,b沒有任何修改。 因為b是一個完全的副本,元素地址均與a不同,a修改,b不受影響 。

總結:

1. 賦值是將一個對象的地址賦值給一個變數,讓變數指向該地址( 舊瓶裝舊酒 )。

2. 淺拷貝是在另一塊地址中建立一個新的變數或容器,但是容器內的元素的地址均是來源物件的元素的地址的拷貝。也就是說新的容器中指向了舊的元素( 新瓶裝舊酒 )。

3. 深拷貝是在另一塊地址中建立一個新的變數或容器,同時容器內的元素的地址也是新開闢的,僅僅是值相同而已,是完全的副本。也就是說( 新瓶裝新酒 )。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.