簡體   English   中英

兩個變量似乎指向同一個列表,即使它們應該是唯一的

[英]Two variables seem to point to the same list, even though they should be unique

我在程序中使用列表,但我不理解以下行為。 我已經開始理解可變性以及它如何影響變量賦值,但我沒有看到這里的問題:

class Test:
    def __init__(self, list_n):
        list_a = list_n[:]
        list_b = list_n[:]
        print(list_a is list_b) # Prints False
        print(list_a is list_n) # Prints False
        print(list_b is list_n) # Prints False

        list_a[0][0] = 1
        print(list_a) # Both of these print [[1,0,0][0,0,0][0,0,0]]
        print(list_b)

def main():
    list_n = [[0,0,0],[0,0,0],[0,0,0]]
    test = Test(list_n)      

if __name__ == '__main__': main()

list_alist_b似乎仍然指向同一個列表,即使我認為我采取了必要的措施來防止這種情況發生。

為什么沒有使用切片表示法來復制我的列表工作?

您的示例不起作用的原因是因為您只創建了list_n淺表副本 列表的淺表副本僅復制“頂級”列表。 淺復制列表不會復制子列表 列表的淺副本是通過調用list上的copy()list.copy() )或使用切片表示法( list[:] )來創建的。

在C級別,當對作為列表的元素進行淺拷貝時,指向列表的指針(稱為PyObject s)正從一個列表復制到另一個列表。 但是,不會復制每個子列表的實際指針,因此list_alist_b都包含指向完全相同的子列表的指針。

說白了,你從來沒有在list_nlist_n每個子列表list_n ,因此list_alist_b仍然包含指向相同子列表的指針。 這可以通過創建list_nlist_n復制”來list_n - 無論嵌套級別如何,原始列表中每個子列表的副本 - 使用copy.deepcopy()

>>> from copy import deepcopy
>>> 
>>> list_n = [[0,0,0],[0,0,0],[0,0,0]]
>>> list_a = deepcopy(list_n)
>>> list_b = deepcopy(list_n)
>>> 
>>> list_a[0][0] = 1
>>> list_a
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> list_b
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> 

我什么時候應該使用deepcopy()

使用deepcopy()的最大缺點之一是“深度復制”淺層嵌套列表需要花費大量時間。

如果您的列表只是淺層嵌套(深度為兩到三層),則應該只使用嵌套列表 deepcopy()而不是deepcopy() 使用這種方法會更有效率(感謝@jonrsharpe指出這一點):

>>> list_n = [[0,0,0],[0,0,0],[0,0,0]]
>>> list_a = [x[:] for x in list_n]
>>> list_b = [x[:] for x in list_n]

使用此方法獲得的效率可以使用標准庫中的timeit模塊觀察:

>>> import timeit
>>> 
>>> setup="from copy import deepcopy; list_n = [[0,0,0],[0,0,0],[0,0,0]]"
>>> timeit.timeit(setup=setup, stmt="deepcopy(list_n)")
24.223977088928223
>>> timeit.timeit(setup=setup, stmt="[x[:] for x in list_n]")
1.2281990051269531
>>>  

但是,如果您的列表更深,則應選擇使用deepcopy() ,即使它看起來有些笨重。 通常永遠不需要犧牲可讀性而不是效率。 此外,隨着列表理解變得越來越復雜, deepcopy()復制deepcopy()的效率開始變小。

為什么deepcopy()這么慢?

deepcopy()比大多數其他方法慢得多(感謝@Felix的問題),因為deepcopy()比簡單的列表理解做了更多的工作。 與列表deecopy()不同, deecopy()必須在任意嵌套列表上工作,可能有deecopy()嵌套。 因此,在淺嵌套列表中使用它是極端的過度殺傷,並且會導致執行時間慢得多。

為了更好地了解deepcopy()在幕后的作用,您可以查看該函數的源代碼,因為它是開源的,可供公眾查看

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM