前面介紹了Python的賦值(對象的引用傳遞),那么Python如何解決原始數(shù)據(jù)在函數(shù)傳遞后不受影響呢,Python提供了淺度拷貝(shallowcopy)和深度拷貝(deepcopy)兩種方式。
·淺拷貝(copy):拷貝父對象,不拷貝對象內(nèi)部的子對象。
·深拷貝(deepcopy):完全拷貝了父對象及其子對象。
淺拷貝
1.不可變數(shù)據(jù)類型
下面對不可變對象整型變量和元組進(jìn)行淺拷貝:
importcopy
a=1
b=copy.copy(a)
print(id(a))
print(id(b))
print(a==b)
print(aisb)
t1=(1,2,3)
t2=tuple(t1)
print(id(t1))
print(id(t2))
print(t1==t2)
print(t1ist2)
執(zhí)行結(jié)果:
50622072
50622072
True
True
55145384
55145384
True
True
不可變對象的拷貝和對象的引用傳遞一樣,a、b指向相同的對象,修改其中一個變量的值不會影響另外的變量,會開辟新的空間。
2.可變數(shù)據(jù)類型
對可變對象list進(jìn)行淺拷貝:
importcopy
l1=[1,2,3]
l2=list(l1)
l3=copy.copy(l1)
l4=l1[:]
print(id(l1))
print(id(l2))
print(l1==l2)
print(l1isl2)
print(id(l3))
print(id(l4))
l1.append(4)
print(id(l1))
print(l1==l2)
print(l1isl2)
執(zhí)行結(jié)果:
48520904
48523784
True
False
48523848
48521032
48520904
False
False
可以看到,對可變對象的淺拷貝會重新分配一塊內(nèi)存,創(chuàng)建一個新的對象,里面的元素是原對象中子對象的引用。改變l1的值不會影響l2,l3,l4的值,它們指向不同的對象。
上面的例子比較簡單,下面舉一個相對復(fù)雜的數(shù)據(jù)結(jié)構(gòu):
importcopy
l1=[[1,2],(4,5)]
l2=copy.copy(l1)
print(id(l1))
print(id(l2))
print(id(l1[0]))
print(id(l2[0]))
l1.append(6)
print(l1)
print(l2)
l1[0].append(3)
print(l1)
print(l2)
執(zhí)行結(jié)果:
1918057951816
1918057949448
2680328991496
2680328991496
[[1,2],(4,5),6]
[[1,2],(4,5)]
[[1,2,3],(4,5),6]
[[1,2,3],(4,5)]
l2是l1的淺拷貝,它們指向不同的對象,因為淺拷貝里的元素是對原對象元素的引用,因此l2中的元素和l1指向同一個列表和元組對象(l1[0]和l2[0]指向的是相同的地址)。l1.append(6)不會對l2產(chǎn)生任何影響,因為l2和l1作為整體是兩個不同的對象,不共享內(nèi)存地址。
l1[0].append(3)對l1中的第一個列表新增元素3,因為l2是l1的淺拷貝,l2中的第一個元素和l1中的第一個元素,共同指向同一個列表,因此l2中的第一個列表也會相對應(yīng)的新增元素3。
這里提一個小問題:如果對l1中的元組新增元素(l1[1]+=(7,8)),會影響l2嗎?
到這里我們知道使用淺拷貝可能帶來的副作用,要避免它就得使用深度拷貝。
深度拷貝
深度拷貝會完整地拷貝一個對象,會重新分配一塊內(nèi)存,創(chuàng)建一個新的對象,并且將原對象中的元素以遞歸的方式,通過創(chuàng)建新的子對象拷貝到新對象中。因此,新對象和原對象沒有任何關(guān)聯(lián),也就是完全拷貝了父對象及其子對象。
importcopy
l1=[[1,2],(4,5)]
l2=copy.deepcopy(l1)
print(id(l1))
print(id(l2))
l1.append(6)
print(l1)
print(l2)
l1[0].append(3)
print(l1)
print(l2)
執(zhí)行結(jié)果:
3026088342280
3026088342472
[[1,2],(4,5),6]
[[1,2],(4,5)]
[[1,2,3],(4,5),6]
[[1,2],(4,5)]
可以看到,l1變化不影響l2,l1和l2完全獨立,沒有任何聯(lián)系。
在進(jìn)行深度拷貝時,深度拷貝deepcopy中會維護(hù)一個字典,記錄已經(jīng)拷貝的對象與其ID。如果字典里已經(jīng)存儲了將要拷貝的對象,則會從字典直接返回。
以上內(nèi)容為大家介紹了Python淺拷貝和深度拷貝,希望對大家有所幫助,如果想要了解更多Python相關(guān)知識,請關(guān)注IT培訓(xùn)機構(gòu):千鋒教育。http://www.jsszjs.cn/