Python對(duì)象的深拷貝和淺拷貝詳解
本文內(nèi)容是在《Python核心編程2》上看到的,感覺很有用便寫出來(lái),給大家參考參考!
淺拷貝
首先我們使用兩種方式來(lái)拷貝對(duì)象,一種是切片,另外一種是工廠方法。然后使用id函數(shù)來(lái)看看它們的標(biāo)示符
# encoding=UTF-8
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
print id(x)
35217032
35227912
29943304
他們的id都不同,按照正常的判斷,三個(gè)不同id的對(duì)象應(yīng)該都是獨(dú)立的。那么我們先給他們改改名看看
# encoding=UTF-8
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
print id(x)
a[0] = 'lisi'
b[0] = 'zhangsan'
print a
print b
35217032
35227912
33547784
['lisi', ['age', 18]]
['zhangsan', ['age', 18]]
對(duì)象a與b分別賦予了不同的名字,下來(lái)我們來(lái)看看給a對(duì)象改一個(gè)年齡
# encoding=UTF-8
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
print id(x)
a[0] = 'lisi'
b[0] = 'zhangsan'
print a
print b
a[1][1] = 25
print a
print b
35217032
35227912
29943304
['lisi', ['age', 18]]
['zhangsan', ['age', 18]]
['lisi', ['age', 25]]
['zhangsan', ['age', 25]]
細(xì)心的朋友應(yīng)該看出來(lái)了,改變a[0]元素與b[0]元素都互不影響,為何改變a[1][1]的元素會(huì)影響b[1][1]的元素呢?
要解開這個(gè)問題,只有先了解深拷貝與淺拷貝。以上實(shí)例中,我們創(chuàng)建的a與b都是從obj對(duì)象的淺拷貝,obj中第一個(gè)元素是字符串屬于不可變類型,第二個(gè)元素是列表屬于可變類型。因此我們進(jìn)行拷貝對(duì)象時(shí),字符串被顯示拷貝重新創(chuàng)建了一個(gè)字符串,而列表只是復(fù)制引用,所以改變列表的元素會(huì)影響所有引用對(duì)象。從下列的id值中,你就能看明白了
# encoding=UTF-8
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
print id(x[0]),id(x[1])
a[0] = 'lisi'
b[0] = 'zhangsan'
for x in obj,a,b:
print id(x[0]),id(x[1])
a[1][1] = 25
b[1][1] = 30
for x in obj,a,b:
print id(x[0]),id(x[1])
32564088 34496008
32564088 34496008
32564088 34496008
32564088 34496008
34574704 34496008
33970672 34496008
32564088 34496008
34574704 34496008
33970672 34496008
復(fù)制對(duì)象的時(shí)候,我們可以看到所有元素的id都一直,我們分別改變了a與b對(duì)象的第一個(gè)字符串元素,因?yàn)樽址遣豢勺儗?duì)象,所以改變后等于新創(chuàng)建,于是a與b的第一個(gè)字符串元素id不一致。而a與b的第二個(gè)元素都是列表可變對(duì)象,所以無(wú)論修改任何一個(gè)id值都表示一個(gè)指針,始終影響其它引用對(duì)象的值。
因此也就為什么修改a對(duì)象的年齡會(huì)影響b對(duì)象的年齡值,或者修改b對(duì)象的年齡值也會(huì)影響a對(duì)象的年齡值,包括obj對(duì)象在內(nèi)。
深拷貝
以上都是淺拷貝,那么我們希望拷貝的對(duì)象是獨(dú)立的,修改時(shí)不要影響其它值,這種我們稱為深拷貝。實(shí)現(xiàn)深拷貝我們需要引用一個(gè)copy模塊,copy模塊有兩個(gè)函數(shù)可用,一個(gè)是copy淺拷貝;另一個(gè)是deepcopy深拷貝。
# encoding=UTF-8
import copy
obj = ['name',['age',18]]
a=copy.deepcopy(obj)
b=copy.deepcopy(obj)
for x in a,b:
print id(x[0]),id(x[1])
a[1][1] = 25
b[1][1] = 30
print a
print b
33612664 35477256
33612664 35477640
['name', ['age', 25]]
['name', ['age', 30]]
使用深拷貝后,列表元素的id不一致,表示獨(dú)立對(duì)象,修改任何一個(gè)列表元素的值都不會(huì)影響其它對(duì)象。
以下是幾點(diǎn)拷貝操作的注意事項(xiàng):
第一、非容器類型(比如數(shù)字、字符串和其它“院子”類型的對(duì)象,像代碼、類型和range對(duì)象等)沒有被拷貝一說(shuō),淺拷貝是用完全切片操作來(lái)完成。
第二、如果元祖變量只包含原子類型對(duì)象,對(duì)它的深拷貝將不會(huì)進(jìn)行。
我們把上面的例子改成元祖,然后使用深拷貝試試
# encoding=UTF-8
import copy
obj = ['name',('age',18)]
a=copy.deepcopy(obj)
b=copy.deepcopy(obj)
for x in a,b:
print id(x),id(x[1])
34703752 34693000
34756616 34693000
相關(guān)文章
Python修改Excel數(shù)據(jù)的實(shí)例代碼
Python修改Excel數(shù)據(jù)的方法。2013-11-11
python基于雙向鏈表實(shí)現(xiàn)LFU算法
這篇文章主要為大家詳細(xì)介紹了python基于雙向鏈表實(shí)現(xiàn)LFU算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
python檢查序列seq是否含有aset中項(xiàng)的方法
這篇文章主要介紹了python檢查序列seq是否含有aset中項(xiàng)的方法,涉及Python針對(duì)序列的相關(guān)判斷技巧,需要的朋友可以參考下2015-06-06
Python實(shí)現(xiàn)連接MySql數(shù)據(jù)庫(kù)及增刪改查操作詳解
這篇文章主要介紹了Python實(shí)現(xiàn)連接MySql數(shù)據(jù)庫(kù)及增刪改查操作,結(jié)合實(shí)例形式詳細(xì)分析了Python安裝PyMySQL模塊及使用PyMySQL模塊進(jìn)行mysql數(shù)據(jù)庫(kù)的連接、增刪改查等相關(guān)操作技巧,需要的朋友可以參考下2019-04-04
Python3讀取UTF-8文件及統(tǒng)計(jì)文件行數(shù)的方法
這篇文章主要介紹了Python3讀取UTF-8文件及統(tǒng)計(jì)文件行數(shù)的方法,涉及Python讀取指定編碼文件的相關(guān)技巧,需要的朋友可以參考下2015-05-05

