拷貝就是拷貝,何來深淺之說?
Python中,對象的賦值,拷貝(深/淺拷貝)之間是有差異的,如果使用的時候不注意,就可能產(chǎn)生意外的結(jié)果
其實這個是由于共享內(nèi)存導(dǎo)致的結(jié)果
拷貝:原則上就是把數(shù)據(jù)分離出來,復(fù)制其數(shù)據(jù),并以后修改互不影響。
先看 一個非拷貝的例子
=賦值:數(shù)據(jù)完全共享(=賦值是在內(nèi)存中指向同一個對象,如果是可變(mutable)類型,比如列表,修改其中一個,另一個必定改變
如果是不可變類型(immutable),比如字符串,修改了其中一個,另一個并不會變
)
l1?=?[1,?2,?3, ['aa',?'bb']]
l2?=?l1l2[0]='aaa'
l2[3][0]='bbb'
print(l1)??
#['aaa', 2, 3, ['bbb', 'bb']]
print (id(l1)==id(l2))??#True
l2 = l1 ,l1 完全賦值給l2 ,l2的內(nèi)存地址與l1 相同,即內(nèi)存完全指向
淺拷貝:數(shù)據(jù)半共享(復(fù)制其數(shù)據(jù)獨立內(nèi)存存放,但是只拷貝成功第一層)
l1= [1,2,3,[11,22,33]]
l2 = l1.copy()
print (l2)
#[1,2,3,[11,22,33]]
l2[3][2]='aaa'
print (l1)
#[1, 2, 3, [11, 22, 'aaa']]
print (l2)
#[1, 2, 3, [11, 22, 'aaa']]
l1[0]= 0
print (l1)
#[0, 2, 3, [11, 22, 'aaa']]
print (l2)
#[1, 2, 3, [11, 22, 'aaa']]
print (id(l1)==id(l2)) #Flase
如上述代碼,l2淺拷貝了l1 ,之后l2把其列表中的列表的元素給修改,從結(jié)果看出,l1也被修改了。但是僅僅修改l1列表中的第一層元素,卻并沒有影響l2。
比較一下l2與l1的內(nèi)存地址:False,說明,l2在內(nèi)存中已經(jīng)獨立出一部分復(fù)制了l1的數(shù)據(jù),但是只是淺拷貝,第二層的數(shù)據(jù)并沒有拷貝成功,而是指向了l1中的第二層數(shù)據(jù)的內(nèi)存地址,所以共享內(nèi)存‘相當(dāng)于‘’等號賦值’‘,所以就會有l(wèi)2中第二層數(shù)據(jù)發(fā)生變化,l1中第二層數(shù)據(jù)也發(fā)生變化

如圖,這就是淺拷貝的原理,l2拷貝l1的時候只拷貝了他的第一層,也就是在其他內(nèi)存中重新創(chuàng)建了l1的第一層數(shù)據(jù),但是l2無法拷貝l1的第二層數(shù)據(jù),也就是列表中的列表,所以他就只能指向l1中的第二層數(shù)據(jù)
由此,當(dāng)修改l1中第二層數(shù)據(jù)的時候,淺拷貝l1的l2中的第二層數(shù)據(jù)也隨之發(fā)生改變
深拷貝:數(shù)據(jù)完全不共享(復(fù)制其數(shù)據(jù)完完全全放獨立的一個內(nèi)存,完全拷貝,數(shù)據(jù)不共享)
?深拷貝就是完完全全復(fù)制了一份,且數(shù)據(jù)不會互相影響,因為內(nèi)存不共享。
深拷貝的方法有
導(dǎo)入模塊
import?copy
l1?=?[1,?2,?3, [11,?22,?33]]#
l2 = copy.copy(l1)?
#淺拷貝
l2?=?copy.deepcopy(l1)
print(l1,'>>>',l2)
l2[3][0]?=?1111
print(l1,">>>",l2)