從新分配一塊內存,建立一個新的對象,裏面的元素是被拷貝對象中子元素的引用。python
import copy # L1 對象內部爲兩個元素: index 0 :[1,2], index 1:(100,200) L1 = [[1, 2], (100, 200)] # 對L1進行淺copy ,此時,獲得一個新的List對象,並賦值給L2, L2 = list(L1) print("L1的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的內存地址爲--2581953960968,第一個元素的地址--2581953961032,第二個元素的地址--2581951586568 # L2的內存地址爲--2581953936904,第一個元素的地址--2581953961032,第二個元素的地址--2581951586568 # 修改共同引用的列表的內容,因爲L1,L2的第一個元素都指向這個列表,所以,L1,L2 對應的元素內容 都發生了變化,可是id是不變的。 L1[0].append(3) print(L1) # [[1, 2, 3], (100, 200)] print(L2) # [[1, 2, 3], (100, 200)] # L1 新增元素 ,L1 和L2 互相獨立,不受影響 L1.append(100) print(L1) # [[1, 2, 3], (100, 200), 100] print(L2) # [[1, 2, 3], (100, 200)] # 元組不可變,所以,元組使用 + ,獲得的是一個新的元祖對象,所以L2內的元組對象id不變,L1內的元組對象id發生了變化。 L1[1] += (500, 600) print(L1) # [[1, 2, 3], (100, 200, 500, 600), 100] print(L2) # [[1, 2, 3], (100, 200)] print("L1的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的內存地址爲--2581953960968,第一個元素的地址--2581953961032,第二個元素的地址--2581952542584 # L2的內存地址爲--2581953936904,第一個元素的地址--2581953961032,第二個元素的地址--2581951586568 # 列表是可變的,+ 號操做,在以前基礎上新增元素,相似列表的extend方法 L1[0] += [3000, 4000] print(L1) # [[1, 2, 3, 3000, 4000], (100, 200, 500, 600), 100] print(L2) # [[1, 2, 3, 3000, 4000], (100, 200)] print("L1的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的內存地址爲--2581953960968,第一個元素的地址--2581953961032,第二個元素的地址--2581952542584 # L2的內存地址爲--2581953936904,第一個元素的地址--2581953961032,第二個元素的地址--2581951586568
實現方式:app
L1=[[100,200],(1000,2000)] L3=list(L1) L4=L1[:] L5=copy.copy(L1) print("L3的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L3), id(L3[0]), id(L3[1]))) print("L4的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L4), id(L4[0]), id(L4[1]))) print("L5的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L5), id(L5[0]), id(L5[1]))) # L3的內存地址爲--2581952584392,第一個元素的地址--2581953960904,第二個元素的地址--2581951626888 # L4的內存地址爲--2581953960968,第一個元素的地址--2581953960904,第二個元素的地址--2581951626888 # L5的內存地址爲--2581953936968,第一個元素的地址--2581953960904,第二個元素的地址--2581951626888
s1=(100,200) s2=tuple(s1) s3=s1[:] s4=copy.copy(s1) print(id(s1)) # 2399341093128 print(id(s2)) # 2399341093128 print(id(s3)) # 2399341093128 print(id(s4)) # 2399341093128
從新分配一塊內存,建立一個新對象,並將被拷貝對象中的全部元素,以遞歸的方式,複製到這個新對象中。新對象和原對象徹底獨立,互不影響。函數
import copy L1=[[1,2],(100,200)] L2=copy.deepcopy(L1) print("L1的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的內存地址爲--{},第一個元素的地址--{},第二個元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的內存地址爲--1665896340552,第一個元素的地址--1665896340616,第二個元素的地址--1665893966024 # L2的內存地址爲--1665896340488,第一個元素的地址--1665896340808,第二個元素的地址--1665893966024 L1[0].append(3) print(L1) # [[1, 2, 3], (100, 200)] print(L2) # [[1, 2], (100, 200)] L1.append(1000) print(L1) # [[1, 2, 3], (100, 200), 1000] print(L2) # [[1, 2], (100, 200)]
l1 = [[1, 2], (30, 40)] l2 = copy.deepcopy(l1) l1.append(100) l1[0].append(3) print(l1) # [[1, 2, 3], (30, 40), 100] print(l2) # [[1, 2], (30, 40)]
這個例子,列表 x 中有指向自身的引用,所以 x 是一個無限嵌套的列表。可是深度拷貝 x 到 y 後,程序並無出現 stack overflow 的現象。這是由於深度拷貝函數 deepcopy 中會維護一個字典,記錄已經拷貝的對象與其 ID。拷貝過程當中,若是字典裏已經存儲了將要拷貝的對象,則會從字典直接返回。code
def deepcopy(x, memo=None, _nil=[]): """Deep copy operation on arbitrary Python objects. See the module's __doc__ string for more info. """ if memo is None: memo = {} d = id(x) # 查詢被拷貝對象x的id y = memo.get(d, _nil) # 查詢字典裏是否已經存儲了該對象 if y is not _nil: return y # 若是字典裏已經存儲了將要拷貝的對象,則直接返回