当前位置:  开发笔记 > 编程语言 > 正文

两个变量似乎指向同一个列表,即使它们应该是唯一的

如何解决《两个变量似乎指向同一个列表,即使它们应该是唯一的》经验,为你挑选了1个好方法。

我在程序中使用列表,但我不理解以下行为.我已经开始理解可变性以及它如何影响变量赋值,但我没有看到这里的问题:

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似乎仍指向同一个列表,即使我想我采取了必要的措施,以防止这种情况发生.



1> Christian De..:

为什么没有使用切片表示法来复制我的列表工作?

您的例子不工作的原因是因为你只作了一个浅拷贝list_n.列表的浅表副本仅复制"顶级"列表.浅复制列表不会复制子列表.名单的副本浅通过调用作出copy()list(list.copy())或使用切片表示法(list[:]).

在C级别,当对作为列表的元素进行浅拷贝时,指向列表的指针(称为PyObjects)正从一个列表复制到另一个列表.对于每个但是子列表的实际指针,不被复制,并且因此list_alist_b既包含指向的确切相同的子列表.

说白了,你从来没有复印件各一份子列表list_n,因此list_alist_b仍然都包含指向同一子列表.这可以通过创建"深度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().使用这种方法会更有效率(感谢@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()是它比大多数其他方法慢得多(感谢@Felix提出要求),因为deepcopy()它比简单的列表理解做得更多.与列表理解不同,deecopy()必须在任意嵌套列表上工作,可能有多层嵌套.因此,在浅嵌套列表中使用它是极端的过度杀伤,并且会导致执行时间慢得多.

为了更好地了解deepcopy()幕后的内容,您可以查看该函数的源代码,因为它是开源的,可供公众查看.


因为它只有一层深而均匀,我怀疑`[l [:] for list in list_n]`比`deepcopy`更有效.
@jonrsharpe我根本不介意!事实上,你完全正确.使用`timeit`模块,定时`deepcopy()`花了大约30.5秒,而你的方法只花了大约1秒钟!感谢更新.
对于更深层次的结构,嵌套列表组合会变得难看,这是真的!然而,它似乎快了两个数量级,所以我想我会提到它.
推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有