我們?nèi)粘Kf的復(fù)制(自己在電腦硬盤上的復(fù)制)就是深復(fù)制(deepcopy),即將被復(fù)制對(duì)象完全再復(fù)制一遍作為獨(dú)立的新個(gè)體單獨(dú)存在。所以改變?cè)斜粡?fù)制對(duì)象不會(huì)對(duì)已經(jīng)復(fù)制出來的新對(duì)象產(chǎn)生影響。
成都創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)定制網(wǎng)站開發(fā),是成都網(wǎng)站維護(hù)公司,為成都酒樓設(shè)計(jì)提供網(wǎng)站建設(shè)服務(wù),有成熟的網(wǎng)站定制合作流程,提供網(wǎng)站定制設(shè)計(jì)服務(wù):原型圖制作、網(wǎng)站創(chuàng)意設(shè)計(jì)、前端HTML5制作、后臺(tái)程序開發(fā)等。成都網(wǎng)站營銷推廣熱線:18982081108
而淺復(fù)制(copy)并不會(huì)產(chǎn)生一個(gè)獨(dú)立的對(duì)象單獨(dú)存在,他只是將原有的數(shù)據(jù)塊打上一個(gè)新標(biāo)簽,所以當(dāng)其中一個(gè)標(biāo)簽指向的數(shù)據(jù)塊就會(huì)發(fā)生變化,另一個(gè)標(biāo)簽也會(huì)隨之改變。這就和我們尋常意義上的復(fù)制有所不同了。
最近在學(xué)習(xí) Python編程,遇到copy和deepcopy感到很困惑,現(xiàn)在針對(duì)這兩個(gè)方法進(jìn)行區(qū)分,一種是淺復(fù)制(copy),一種是深度復(fù)制(deepcopy)。
首先說一下deepcopy,所謂的深度復(fù)制,在這里我理解的是完全復(fù)制然后變成一個(gè)新的對(duì)象,復(fù)制的對(duì)象和被復(fù)制的對(duì)象沒有任何關(guān)系,彼此之間無論怎么改變都相互不影響。
然后說一下copy,在這里我分為兩類來說,一種是字典數(shù)據(jù)類型的copy函數(shù),一種是copy包的copy函數(shù)。
一、字典數(shù)據(jù)類型的copy函數(shù),當(dāng)簡單的值替換的時(shí)候,原始字典和復(fù)制過來的字典之間互不影響,但是當(dāng)添加,刪除等修改操作的時(shí)候,兩者之間會(huì)相互影響。
(1)值替換
[python]?view plain?copy
import?copy
d?=?{
'name'?:?['An','Assan']
}
c?=?d.copy()
dc?=?copy.deepcopy(d)
d['name']?=?['an']
print?c
print?d
print?dc
結(jié)果如下:
[python]?view plain?copy
{'name':?['An',?'Assan']}
{'name':?['an']}
{'name':?['An',?'Assan']}
(2)值修改
[python]?view plain?copy
import?copy
d?=?{
'name'?:?['An','Assan']
}
c?=?d.copy()
dc?=?copy.deepcopy(d)
d['name'].append('shu')
print?c
print?d
print?dc
結(jié)果如下:
[python]?view plain?copy
{'name':?['An',?'Assan',?'shu']}
{'name':?['An',?'Assan',?'shu']}
{'name':?['An',?'Assan']}
二、copy包中的copy函數(shù),無論是修改還是值替換兩者之間都互不影響。
[python]?view plain?copy
import?copy
seq?=?[1,2,3]
seq1?=?seq
seq2?=?copy.copy(seq)
seq3?=?copy.deepcopy(seq)
seq.append(4)
seq2[2]?=?5
print?seq,seq1,seq2,seq3
結(jié)果如下:
[python]?view plain?copy
[1,?2,?3,?4]?[1,?2,?3,?4]?[1,?2,?5]?[1,?2,?3]
在上面代碼中,sql1 = seq其實(shí)是同是指向同一個(gè)對(duì)象地址,使用的同一個(gè)對(duì)象引用。
對(duì)于Python的初學(xué)者,在對(duì)象的使用過程中,由于對(duì)變量的賦值和對(duì)象的復(fù)制中的概念模糊,導(dǎo)致程序出錯(cuò)。
例如,下面的代碼:
輸出結(jié)果為:
a = [6,2,3,4,5],
b = [6,2,3,4,5],
c = [1,2,3,4,5]
a等于b?True
a等于c?True
a是b?True
a是c? False
可以看到,a,b, c所指向的對(duì)象的值都相同(a==b為True). a和b都是代表同一個(gè)對(duì)象(a is b為True)。當(dāng)我們通過變量b對(duì)該列表進(jìn)行修改時(shí),由于a也指向該列表,所以當(dāng)打印a,b時(shí),我們得到相同的值。 而a和c則是代表不同的對(duì)象(a is c為False),所以修改b所指向得列表不會(huì)改變c梭子鄉(xiāng)的列表的值.
在Python中,所有的變量都代表了對(duì)象,即便是簡單的數(shù)字類型(int, float, bool),也是以對(duì)象的形式存在的。我們看下面的代碼:
輸出結(jié)果是:
a==b為True
a is b為True
可見,a, b都是指向同一個(gè)對(duì)象。接下來,進(jìn)行下面的操作,
輸出結(jié)果是:
a = 1, b = 2
a is b為False
與前面的列表不同,當(dāng)我們對(duì)b做修改時(shí),實(shí)際上是給b賦予了一個(gè)新生成的對(duì)象,對(duì)數(shù)值類型來說,所有的數(shù)值運(yùn)算都會(huì)創(chuàng)建一個(gè)數(shù)值對(duì)象,并將這個(gè)對(duì)象指定給變量。因此,a與b指向了不同的對(duì)象,數(shù)值也不同。
再回過頭來看列表對(duì)象,
我們知道,b是與a指向同一對(duì)象的變量,使用b對(duì)該對(duì)象進(jìn)行修改,與使用a對(duì)該對(duì)象進(jìn)行修改,效果是完全一樣的。如果我們需要需要一個(gè)與a完全相同又與a相互獨(dú)立的列表,那么就需要復(fù)制這個(gè)對(duì)象,也就是新建一個(gè)內(nèi)容和源對(duì)象相同的對(duì)象。
對(duì)于列表來說,最簡單的復(fù)制方法是通過下標(biāo)索引的方式創(chuàng)建新的列表:
對(duì)于各種數(shù)據(jù)類型通用的對(duì)象拷貝復(fù)制,我們可以使用python內(nèi)建的copy模塊。
對(duì)于復(fù)雜對(duì)象(如嵌套列表)的復(fù)制,則需要注意區(qū)分淺拷貝和深拷貝。我們來看下面的代碼:
得到的結(jié)果是:
a[0] is b[0]為 True
a[0] is c[0]為 False
a = [[-1, 2, 3], [4, 5, 6]]
b = [[-1, 2, 3], [7, 8, 9]]
c = [[1, 2, 3], [4, 5, 6]]
a[1] is b[1]為False
從上面的代碼我們可以看到,copy函數(shù)為淺拷貝,只拷貝了對(duì)象的外層,而對(duì)象內(nèi)部所包含的對(duì)象仍然指向原有的對(duì)象。而deepcopy則為深拷貝,對(duì)象內(nèi)部的對(duì)象也進(jìn)行了復(fù)制。
以上我們對(duì)變量的賦值和對(duì)象的復(fù)制做了更加深入的分析。在具體的使用中,我們需要根據(jù)具體來決定使用賦值、淺拷貝、深拷貝。