繁体   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