== 與 is 的區別
- == :判斷 值,比較兩個對象是否相等
- is :判斷 地址,比較兩個引用是否指向了同一個對象(引用比較)
賦值、深拷貝、淺拷貝的區別
首先,不可變數據類型的內存都指向同一個地址,所以深拷貝和淺拷貝對於不可變數據類型而言都是無意義的。
對於不可變數據類型:
import copy
# 深拷貝
a = 'python'
b = copy.deepcopy(a)
print(a, id(a)) # python 2796288573600
print(b, id(b)) # python 2796288573600
# 淺拷貝
c = copy.copy(a)
print(a, id(a)) # python 2796288573600
print(c, id(c)) # python 2796288573600
賦值
是對原變量的完全複製,內存地址一樣,如果原來的改變,後面的也會跟着變。
x = [123, 456, 789]
y = x
print(x, id(x)) # [123, 456, 789] 1885210370632
print(y, id(y)) # [123, 456, 789] 1885210370632
x[0] = 1
print(x, id(x)) # [1, 456, 789] 1885210370632
print(y, id(y)) # [1, 456, 789] 1885210370632
深拷貝
對於可變數據類型:
import copy
a = [123, [1, 2, 3]]
b = copy.deepcopy(a)
print(a, id(a), id(a[0]), id(a[1])) # [123, [1, 2, 3]] 2734749304648 140719688872400 2734749304584
print(b, id(b), id(b[0]), id(b[1])) # [123, [1, 2, 3]] 2734749395720 140719688872400 2734749502728
a[1][0] = 5 # 修改嵌套列表的元素
print(a, id(a), id(a[0]), id(a[1])) # [123, [5, 2, 3]] 2734749304648 140719688872400 2734749304584
print(b, id(b), id(b[0]), id(b[1])) # [123, [1, 2, 3]] 2734749395720 140719688872400 2734749502728
我們可以看到,深拷貝是直接創建了一個新的對象,所以地址不同,將原對象所有的值/元素拷貝過來,而且是對其所有層次的拷貝(包括嵌套列表)
- 將原對象的“ 值/元素 ”賦給新對象,新對象中元素的地址與原對象的 地址不同
- 是對原對象 所有層次 的拷貝(遞歸)
- 與原對象沒有任何關係,如果原對象發生變化,深拷貝後的新對象 不會發生改變
淺拷貝
對於可變數據類型:
import copy
a = [123, [1, 2, 3]]
b = copy.copy(a)
print(a, id(a), id(a[0]), id(a[1])) # [123, [1, 2, 3]] 2944705742536 140719688872400 2944705742472
print(b, id(b), id(b[0]), id(b[1])) # [123, [1, 2, 3]] 2944705837704 140719688872400 2944705742472
a[1][0] = 5 # 修改嵌套列表的元素
print(a, id(a), id(a[0]), id(a[1])) # [123, [5, 2, 3]] 2944705742536 140719688872400 2944705742472
print(b, id(b), id(b[0]), id(b[1])) # [123, [5, 2, 3]] 2944705837704 140719688872400 2944705742472
我們可以看到,兩個列表的元素指向同一地址,拷貝的只是原列表元素的引用。
當我們修改嵌套列表的元素時,新列表中的嵌套列表也會發生改變,這是因爲淺拷貝只拷貝了表面一層列表,而嵌套列表並沒有進行拷貝,所以修改嵌套列表之後,新列表也會變。
- 將原對象的 引用 賦給新對象,新對象中元素的地址與原對象的 地址相同
- 是對原對象 頂層 的拷貝(表面一層)
- 由於只拷貝了表面一層,當原對象中的嵌套對象發生改變時,新對象也 會發生改變