可變與不可變型別
前面介紹list時提到在python中數據類型分為可變與不可變型別:
可變物件:該物件所指向記憶體中的值可以被改變
不可變物件:該物件所指向記憶體中的值不可以被改變,所以當變數指向的值改變時,等於將原來的值複製一份後存於一個新的地址,變數再指向這個新的地址
等號 = 賦值
在 list 中使用等號 = 賦值時,由於list為可變物件,實際行為是建立該list的引用(別名)
#%% list copy pass by reference
a = [1,2,3]
a_ref = a
a.append(4)
print("a: ", a)
print("a_ref: ", a)
由上述程式碼可知
由於a_ref為a的引用,指向的記憶體位置相同,所以在修改a_ref時也會一併修改到a,如果你的原意是想要一份獨立於a的複製,常常一個不小心沒注意產生bug! 程式寫到一半發現怎麼a_ref也被修改了卻找不出原因,吃了悶虧!這時候就需要談談list的淺複製與深複製了
這個單元談到的淺複製與深複製也會受到這個性質的影響,簡單來說,淺與深的區別:
一般 copy
三種方法
#%% list copy
a_list = list(a)
a_index = a[:]
a_copy = a.copy()
a.append(5)
print("Shallow copy")
print("a_list: ", a_list)
print("a_index: ", a_index)
print("a_copy: ", a_copy)
深複製 deep copy
需要import copy模組,裡面有deepcopy函式可以用
import copy
a = [1, [2,3]]
a_deepcopy = copy.deepcopy(a)
淺複製與深複製 Shallow copy and deep copy 的差別
淺複製與深複製的關鍵差別在於,複製的變數中是否有可變型別
#%% Shallow copy and deep copy
import copy
a = [1, [2,3]]
a_ref = a
a_shallowcopy = copy.copy(a)
a_deepcopy = copy.deepcopy(a)
print("{:<15}{:<20}{}".format("a:", f"{a}", f"id:{id(a_ref)}"))
print("{:<15}{:<20}{}".format("a_shallow_copy:", f"{a_shallowcopy}", f"id:{id(a_shallowcopy)}"))
print("{:<15}{:<20}{}".format("a_deepcopy:", f"{a_deepcopy}", f"id:{id(a_deepcopy)}"))
a[0] = 4
print("\nChange immutable part: a[0] = 4")
print("{:<15}{:<20}{}".format("a:", f"{a}", f"id:{id(a_ref)}"))
print("{:<15}{:<20}{}".format("a_shallow_copy:", f"{a_shallowcopy}", f"id:{id(a_shallowcopy)}"))
print("{:<15}{:<20}{}".format("a_deepcopy:", f"{a_deepcopy}", f"id:{id(a_deepcopy)}"))
其中 a[0] 為數字,即為不可變型別,則深/淺複製沒有差別
讓我們看看如果修改可變型別的內容會發生什麼事?接續上段程式碼:
a[1][1] = 5
print("\nChange mutable part: a[1][1] = 5")
print("{:<20}{:<20}{}".format("a:", f"{a}", f"id:{id(a_ref)}"))
print("{:<20}{:<20}{}".format("a_shallow_copy:", f"{a_shallowcopy}", f"id:{id(a_shallowcopy)}"))
print("{:<20}{:<20}{}".format("a_deepcopy:", f"{a_deepcopy}", f"id:{id(a_deepcopy)}"))
print("\nCheck variable id at deep level")
print("{:<20}{:<20}{}".format("a[1][1]:", f"{a[1][1]}", f"id:{id(a[1][1])}"))
print("{:<20}{:<20}{}".format("a_shallowcopy[1][1]:", f"{a_shallowcopy[1][1]}", f"id:{id(a_shallowcopy[1][1])}"))
print("{:<20}{:<20}{}".format("a_deepcopy[1][1]:", f"{a_deepcopy[1][1]}", f"id:{id(a_deepcopy[1][1])}"))
其中 a[1][1] 為list,即為可變型別,可以發現淺複製 (shallow copy) 被改變了,而深複製 (deep copy) 則沒有被改變,故得知:
Python中的淺複製(shallow copy)和深複製(deep copy)
https://www.itread01.com/content/1544614591.html