python list拷貝賦值問題

在python中,用等號或者append方法進行list的賦值,實際上是將原list的引用賦給了新的變量,在後續使用append方法改變這兩個list中的任何一個時,另一個也會同時改變:

b = [0,1,2]
a = b
b.append(3)
print(a)
print(b)
>>a = [0,1,2,3]
>>b = [0,1,2,3]
a.append(4print(a)
print(b)
>>a = [0,1,2,3,4]
>>b = [0,1,2,3,4]
a[0]=5
>>a = [5,1,2,3,4]
>>b = [5,1,2,3,4]

用append方法把b添加進a也會發生同樣的情況:

a = []
b = [0,1,2]
a.append(b)
b.append(3)
print(a)
print(b)
>>a = [[0,1,2,3]]
>>b = [0,1,2,3]
a[0].append(4print(a)
print(b)
>>a = [[0,1,2,3,4]]
>>b = [0,1,2,3,4]

避免這種情況的方法是用另一個變量把b給copy出來:

b = [0,1,2]
c = b.copy()
a = c
b.append(3)
print(a)
print(b)
print(c)
>>a = [0,1,2]
>>b = [0,1,2,3]
>>c = [0,1,2]
a.append(4)
print(a)
print(b)
print(c)
>>a = [0,1,2,4]
>>b = [0,1,2,3]
>>c = [0,1,2,4]

把a=c這行換成a.append(c)情況類似,但是這好像是append這類直接修改列表的方法纔會出現的(除append之外還有pop),如果重新給b賦其他值,則不會出現上述問題:(應該是重新賦值時新建了一塊地址叫b,切斷了a和之前的變量b的關係)

b = [0,1,2]
a = b
b = b[1:]
print(a)
print(b)
>>a = [0,1,2]
>>b = [1,2]
b = [3,4,5]
print(a)
print(b)
>>a = [0,1,2]
>>b = [3,4,5]

如果b是個二維list呢?

b = [[0,1],[2,3]]
a = b.copy()
id(a)==id(b)
>>False
id(a[0])==id(b[0])
>>True

也就是說使用copy的時候,只是把a和b的地址分開了,他們裏面實際的子列表還是引用的關係,修改其中一個子列表必然會影響到另一個:

a[0].append(2)
print(a)
print(b)
>>a = [[0,1,2],[2,3]]
>>b = [[0,1,2],[2,3]]

但是修改a卻不會同時修改b:

a.append(4)
>>a = [[0,1,2],[2,3],4]
>>b = [[0,1,2],[2,3]]

所以遇到二維list的時候乖乖用deepcopy()吧。
總結一下:
1.用等號(或appne)將list賦值:a=b(a.append(b)),a和b互爲引用關係,id(a)==id(b), id(a[0])==id(b[0])。
2.用copy將list賦值:a=b.copy(),則id(a)!=id(b), id(a[0])==id(b[0])。
3.當id(a)==id(b)時,直接修改a如a.append(x)這類方法,會同時修改b,改變a中的值如a[0]=x,也會同時修改b。
4.當id(a)!=id(b), id(a[0])==id(b[0])時,直接修改a如a.append(x)這類方法,或者修改a[0],都不會同時修改b,但操作到a[0]中的元素,改變a[0]中的值如a[0][0]=x,會同時修改b。
5.也就是說,當兩個變量的某一層次是引用關係時,使用append、pop修改當前層級會同時修改另一變量,使用直接賦值修改當前層級不會同時修改另一變量。當兩個變量的某一層次是引用關係時(id(a)==id(b)),使用賦值修改下一層級的值(a[0]=x),會同時修改另一變量。
6.用深拷貝a=b.deepcopy()肯定沒錯。
感覺list真是個神奇的東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章