天天看點

python可變元素list在程式中的注意事項1 list的可變性2 擴充總結

1 list的可變性

在python程式中,清單list的存貯方式與int的存貯方式是不同的,換句話說,python中可變類型的存儲方式與不可變類型的存儲方式是不同的。

例如,對于單一的元素,有如下操作時:

a = 1
b = a
b = 5
print(a, b)
print(id(a),id(b))  # 列印兩個變量的位址
           

輸出>> 1 5

>> 140731421349024 140731421348896

即對整型變量的指派相當于一個真正的複制過程,兩個變量有了兩個不同的記憶體位址,其實是因為第3句把第二句覆寫掉了。

而對清單元素進行指派時:

a = [[0,1,2],2,3]
b = a
b[0] = 100
print(a, b)
print(id(a),id(b))  # 列印兩個變量的位址
           

輸出>> [100, 2, 3] [100, 2, 3]

>> 2847777749608 2847777749608

也就是說清單的指派本質上是名稱多了一個,換句話說,就是清單的名字多了一個,清單還是原來那個清單。兩個變量具有相同的記憶體位址。

下面看一下.copy()方法:

a = [1,2,3]
b = a.copy()
b[0] = 100
print(a, b)
print(id(a),id(b))  # 列印兩個變量的位址
           

輸出:>> [1, 2, 3] [100, 2, 3]

>> 2744646268360 2744646268744

看起來問題得到了解決,兩個變量記憶體位址也不一樣了,然而.cpoy()都叫它淺拷貝,原因在于如下所示:

a = [[0,1,2],2,3]
b = a.copy()
b[0][1] = 100
print(a, b)
print(id(a),id(b))  # 列印兩個變量的位址
print(id(a[0]), id(b[0]))  # 列印兩個變量中變量的位址
           

輸出:>> [[[0, 100, 2], 2, 3] [[0, 100, 2], 2, 3]

>> 2649294660232 2649295880648

>> 2649294660168 2649294660168

可以看到,.copy()方法隻是将第一層清單的元素完全拷貝了一份新的記憶體,再多一層的清單就沒有拷貝了,是以稱它為淺拷貝。

當清單隻有一維時,是可以使用淺拷貝的。

深拷貝:

import copy
a = [[0,1,2],2,3]
b = copy.deepcopy(a)
b[0][1] = 100
print(a, b)
print(id(a),id(b))  # 列印兩個變量的位址
print(id(a[0]), id(b[0]))  # 列印兩個變量中變量的位址
           

輸出:>> [[0, 1, 2], 2, 3] [[0, 100, 2], 2, 3]

>> 2521760495496 2521760589768

>> 2521760495112 2521760547336

深拷貝完全實作了我們想要的拷貝指派。

2 擴充總結

類似于list有上述特點的還有集合set 、字典dict,即可變元素,因為隻有可變元素在指派後修改之後才可能出現上述問題,不可變元素要不整個元素修改,要不然不改變,不存在上述問題。

指派語句的本質是為變量多起一個名字,即多一個記憶體指針,【最大的用處在于變量有了新名字原來的名字就可以删除了】。

類似于指派語句出現的問題還可能出現在函數傳參過程中,把原清單當作函數參數傳入函數時,如果函數中清單發生修改,原清單也會跟着修改。