前言
在Python中,Python對象的賦值蔼囊,深淺拷貝之間是有差異的,今天就來總結(jié)一下三者之間的區(qū)別.
對象賦值
直接看一下代碼(Python3):
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = list1
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list2[2] is list1[2]
1
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print([id(element) for element in list1])
print([id(element) for element in list2])
2
現(xiàn)在簡單分析一下上面的代碼:
- 創(chuàng)建list對象賦值給為list1變量
- 然后把list1賦值給變量list2瞻想,實際上list2變量將指向list1變量對應(yīng)的對象(內(nèi)存地址)压真,也就是說"list2 is list1","list2[i] is list1[i]"蘑险,Python中滴肿,對象的賦值都是進行對象引用(內(nèi)存地址)傳遞
3.修改list[0]和list[2]的子list值,由于str是不可變類型佃迄,所以修改list[0]時會更換新舊對象泼差,產(chǎn)生一個新的地址贵少。如下圖:
image.png
淺拷貝
下面看一下淺拷貝的代碼:
import copy
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = copy.copy(list1)
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list1[2] is list1[2]
4.jpg
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
5
繼續(xù)分析上面的的代碼:
1.當(dāng)變量list1淺拷貝給變量list2的時候,就相當(dāng)于創(chuàng)建一個新對象堆缘,兩者的id不同滔灶,因此list1 is not list2
2.然而,list2中的元素id是一樣的吼肥。因此說明录平,淺拷貝中的對象的元素是之前的原始元素的引用,所以list1[i] is list2
3.當(dāng)對list1進行修改時缀皱,因為list1的第一個元素是不可變對象斗这,所以會使用一個新的對象
4330292760
,而list2還是指向原始元素的引用4330291808
啤斗;當(dāng)修改第三個元素時表箭,由于是可變對象,所以不會產(chǎn)生一個新的對象钮莲,只修改里面的元素免钻,所以還是4331291992
,如圖image.png
深拷貝
下面看一下深拷貝:
import copy
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = copy.deepcopy(list1)
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list1[2] is list1[2]
6
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
7
分析一下代碼:
1.深拷貝崔拥,不僅創(chuàng)建一個新的對象list1极舔,list1 is not list2
2.還會對對象中的可變元素創(chuàng)建新的對象,所以list1[2] is not list2[2]
3.list1[0]修改元素握童,會創(chuàng)建一個新的對象
4329244408
,list2[0]沒有改變姆怪,還是4329243232
,所以list1修改不會影響list2
image.png
注意:
1.對于非容器類型(如數(shù)字、字符串澡绩、和其他'原子'類型的對象)沒有拷貝這一說
也就是說稽揭,對于這些類型,"obj is copy.copy(obj)" 肥卡、"obj is copy.deepcopy(obj)"
- 如果元祖變量只包含原子類型對象溪掀,則不能深拷貝,看下面的例子:
import copy
list1 = ('a', 'b', 'c')
list2 = copy.deepcopy(list1)
print(list1 is list2) #True
總結(jié)
本文介紹了對象的賦值和拷貝步鉴,以及它們之間的差異:
1.Python中對象的賦值都是進行對象引用(內(nèi)存地址)傳遞
2.使用copy.copy()揪胃,可以進行對象的淺拷貝,它復(fù)制了對象氛琢,但對于對象中的元素喊递,依然使用原始的引用.
3.如果需要復(fù)制一個容器對象,以及它里面的所有元素(包含元素的子元素)阳似,可以使用copy.deepcopy()進行深拷貝
4.對于非容器類型(如數(shù)字骚勘、字符串、和其他'原子'類型的對象)沒有被拷貝一說
5.如果元祖變量只包含原子類型對象,則不能深拷貝