gpt4 book ai didi

python copy.deepcopy 列表看起来很浅

转载 作者:行者123 更新时间:2023-11-30 22:31:26 26 4
gpt4 key购买 nike

我正在尝试初始化表示 3x3 数组的列表列表:

import copy
m = copy.deepcopy(3*[3*[0]])
print(m)
m[1][2] = 100
print(m)

输出是:

[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 100], [0, 0, 100], [0, 0, 100]]

这不是我所期望的,因为每行的最后一个元素是共享的!我确实通过使用得到了我需要的结果:

m = [ copy.deepcopy(3*[0]) for i in range(3) ]

但我不明白为什么第一个(也是更简单的)形式不起作用。 deepcopy 不应该是深的吗?

最佳答案

问题是 deepcopy保留一个备忘录,其中包含已复制的所有实例。这是为了避免无限递归和有意共享对象。因此,当它尝试深度复制第二个子列表时,它会发现它已经复制了它(第一个子列表),并且只是再次插入第一个子列表。简而言之,deepcopy 并不能解决“共享子列表”问题!

引用文档:

Two problems often exist with deep copy operations that don’t exist with shallow copy operations:

  • Recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) may cause a recursive loop.
  • Because deep copy copies everything it may copy too much, such as data which is intended to be shared between copies.

The deepcopy() function avoids these problems by:

  • keeping a “memo” dictionary of objects already copied during the current copying pass; and
  • letting user-defined classes override the copying operation or the set of components copied.

(强调我的)

这意味着deepcopy将共享引用视为意图。例如考虑一下这个类:

from copy import deepcopy

class A(object):
def __init__(self, x):
self.x = x
self.x1 = x[0] # intentional sharing of the sublist with x attribute
self.x2 = x[1] # intentional sharing of the sublist with x attribute

a1 = A([[1, 2], [2, 3]])
a2 = deepcopy(a1)
a2.x1[0] = 10
print(a2.x)
# [[10, 2], [2, 3]]

忽略该类没有多大意义,因为它故意共享其 xx1x2 属性之间的引用。如果 Deepcopy 通过对每个引用进行单独的复制来破坏这些共享引用,那就很奇怪了。这就是为什么文档提到这是“复制太多,例如要在副本之间共享的数据”问题的“解决方案”。

回到您的示例:如果您想要共享引用,最好完全避免它们:

m = [[0]*3 for _ in range(3)]

在您的情况下,内部元素是不可变的,因为 0 是不可变的 - 但如果您处理最内部列表内的可变实例,您也必须避免内部列表乘法:

m = [[0 for _ in range(3)] for _ in range(3)] 

关于python copy.deepcopy 列表看起来很浅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45820614/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com