python copy.deepcopy列表似乎很浅 [英] python copy.deepcopy lists seems shallow

查看:148
本文介绍了python copy.deepcopy列表似乎很浅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to initialize a list of lists representing a 3x3 array:

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]]

自共享每一行的最后一个元素以来,这并不是我所期望的!我确实使用以下方法得到了我需要的结果:

which is not what I expected since the last elements of each row are shared! I did get the result I need by using:

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

但我不明白为什么第一个(和更简单的)表单没有工作。是不是 deepcopy 应该很深?

but I don't understand why the first (and simpler) form does not work. Isn't deepcopy supposed to be deep?

推荐答案

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

The problem is that deepcopy keeps a memo that contains all instances that have been copied already. That's to avoid infinite recursions and intentional shared objects. So when it tries to deepcopy the second sublist it sees that it has already copied it (the first sublist) and just inserts the first sublist again. In short deepcopy doesn't solve the "shared sublist" problem!

引用文档:


深度复制操作经常存在两个问题,而深度复制操作却不存在浅表复制操作:

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.

deepcopy()函数通过以下方法避免了这些问题:

The deepcopy() function avoids these problems by:


  • 保留当前复制过程中已复制对象的备忘录字典通过;和

  • 让用户定义的类覆盖复制操作或复制的组件集。

(强调我的意思)

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

That means that deepcopy regards shared references as intention. For example consider the class:

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]]

忽略该类没有多大意义,因为该类有意在 x x1 x2 属性。如果 deepcopy 通过对每个共享引用进行单独复制而破坏了这些共享引用,那将很奇怪。因此,文档将其称为解决方案,

Neglecting that the class doesn't make much sense as is it intentionally shares the references between its x and x1 and x2 attribute. It would be weird if deepcopy broke those shared references by doing a separate copy of each of these. That's why the documentation mentions this as a "solution" to the problem of "copy too much, such as data which is intended to be shared between copies.".

回到您的示例:如果您不想要想要复制太多的问题,例如打算在副本之间共享的数据。 以便共享参考,最好完全避免使用它们:

Back to your example: If you don't want to have shared references it would be better to avoid them completely:

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

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

In your case the inner elements are immutable because 0 is immutable - but if you deal with mutable instances inside the innermost lists you must have to avoid the inner list multiplication as well:

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

这篇关于python copy.deepcopy列表似乎很浅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆