【问题标题】:What is the purpose of deepcopy's second parameter, memo?deepcopy的第二个参数memo的作用是什么?
【发布时间】:2009-12-23 03:37:56
【问题描述】:
from copy import* 
a=[1,2,3,4]
c={'a':'aaa'}
print c
#{'a': 'aaa'}
b=deepcopy(a,c)
print b

print c
# print {'a': 'aaa', 10310992: 3, 10310980: 4, 10311016: 1, 11588784: [1, 2, 3, 4, [1, 2, 3, 4]], 11566456: [1, 2, 3, 4], 10311004: 2}

为什么要打印那个

请尽量使用代码,而不是文字,因为我的英文不是很好,谢谢

在 django.utils.tree.py 中

def __deepcopy__(self, memodict):
        """
        Utility method used by copy.deepcopy().
        """
        obj = Node(connector=self.connector, negated=self.negated)
        obj.__class__ = self.__class__
        obj.children = deepcopy(self.children, memodict)
        obj.subtree_parents = deepcopy(self.subtree_parents, memodict)
        return obj



import copy
memo = {}
x1 = range(5)
x2=range(6,9)
x3=[2,3,4,11]
y1 = copy.deepcopy(x1, memo)
y2=copy.deepcopy(x2, memo)
y3=copy.deepcopy(x3,memo)
print memo
print id(y1),id(y2),id(y3)
y1[0]='www'
print y1,y2,y3
print memo

打印:

{10310992: 3, 10310980: 4, 10311016: 1, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10311004: 2}
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10310932: 8, 10311004: 2}
11572408 11581280 11580960
['www', 1, 2, 3, 4] [6, 7, 8] [2, 3, 4, 11]
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: ['www', 1, 2, 3, 4], 10310932: 8, 10311004: 2}

【问题讨论】:

    标签: python


    【解决方案1】:

    这是memo dict,其中保留了 id 到对象的对应关系,以完美地重建复杂的对象图。很难“使用代码”,但是,让我们尝试一下:

    >>> import copy
    >>> memo = {}
    >>> x = range(5)
    >>> y = copy.deepcopy(x, memo)
    >>> memo
    {399680: [0, 1, 2, 3, 4], 16790896: 3, 16790884: 4, 16790920: 1,
     438608: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 16790932: 0, 16790908: 2}
    >>> 
    

    >>> id(x)
    399680
    >>> for j in x: print j, id(j)
    ... 
    0 16790932
    1 16790920
    2 16790908
    3 16790896
    4 16790884
    

    所以你看到的 ID 是完全正确的。另外:

    >>> for k, v in memo.items(): print k, id(v)
    ... 
    399680 435264
    16790896 16790896
    16790884 16790884
    16790920 16790920
    438608 435464
    16790932 16790932
    16790908 16790908
    

    您会看到(不可变)整数的标识。

    所以这是一个图表:

    >>> z = [x, x]
    >>> t = copy.deepcopy(z, memo)
    >>> print id(t[0]), id(t[1]), id(y)
    435264 435264 435264
    

    所以你会看到所有的子副本都是与 y 相同的对象(因为我们重用了备忘录)。

    【讨论】:

    【解决方案2】:

    上面没有人给出如何使用它的好例子。

    这是我的工作:

    def __deepcopy__(self, memo):
        copy = type(self)()
        memo[id(self)] = copy
        copy._member1 = self._member1
        copy._member2 = deepcopy(self._member2, memo)
        return copy
    

    其中member1 是不需要深度复制的对象(如字符串或整数),member2 是需要深度复制的对象,如另一种自定义类型或列表或字典。

    我在高度复杂的对象图上使用了上面的代码,效果很好。

    如果你还想让你的类可腌制(用于文件保存/加载),getstate / setstate 没有类似的备忘录参数,换句话说,腌制系统会以某种方式跟踪已引用的对象,因此您无需担心。

    以上内容适用于您继承自的 PyQt5 类(以及酸洗 - 例如,我可以深度复制或酸洗自定义 QMainWindow、QWidget、QGraphicsItem 等)

    如果您的构造函数中有一些创建新对象的初始化代码,例如创建新 CustomScene(QGraphicsScene) 的 CustomWidget(QWidget),但您想将场景从一个 CustomWidget 腌制或复制到新的一,然后一种方法是在您的__init__ 中创建一个new=True 参数并说:

    def __init__(..., new=True):
        ....
        if new:
           self._scene = CustomScene()
    
    def __deepcopy__(self, memo):
        copy = type(self)(..., new=False)
        ....
        copy._scene = deepcopy(self._scene, memo)
        ....
    

    这样可以确保您不会两次创建 CustomScene(或一些进行大量初始化的大类)!您还应该在 __setstate__ 方法中使用相同的设置 (new=False),例如:

     def __setstate__(self, data):
         self.__init__(...., new=False)
         self._member1 = data['member 1']
         .....
    

    还有其他方法可以解决上述问题,但这是我融合并经常使用的方法。

    为什么我也谈到了酸洗?因为您通常在任何应用程序中都需要这两者,并且您同时维护它们。如果您将成员添加到您的类中,则将其添加到 setstate、getstate、 深度复制代码中。我会规定,对于您创建的任何新类,如果您打算在应用程序中复制/粘贴文件保存/加载,则创建上述三种方法。另一种选择是 JSON 并自己保存/加载,但是你还有很多工作要做,包括记忆。

    所以要支持以上所有,您需要__deepcopy__, __setstate__, and __getstate__ 方法并导入 deepcopy:

    from copy import deepcopy
    

    ,当您编写 pickle 加载器/保护程序函数(调用 pickle.load()/ pickle.dump() 以加载/保存对象层次结构/图形)时,请执行 import _pickle as pickle 以获得最佳速度(_pickle 是一些更快的 C impl,即通常与您的应用要求兼容)。

    【讨论】:

    • 糟糕:任何使用上述 sn-p 进行深度复制方法的人。应该是:memo[id(self)] = copy 而不是 self。我编辑了帖子。
    【解决方案3】:

    您可以通过查看 Python 在线文档了解更多信息:

    http://docs.python.org/library/copy.html

    deepcopy() 函数是递归的,它将通过一个深度嵌套的对象向下工作。它使用字典来检测它以前见过的对象,以检测无限循环。你应该忽略这本字典。

    class A(object):
        def __init__(self, *args):
            self.lst = args
    
    class B(object):
        def __init__(self):
            self.x = self
    
    def my_deepcopy(arg):
        try:
            obj = type(arg)()  # get new, empty instance of type arg
            for key in arg.__dict__:
                obj.__dict__[key] = my_deepcopy(arg.__dict__[key])
            return obj
        except AttributeError:
            return type(arg)(arg)  # return new instance of a simple type such as str
    
    a = A(1, 2, 3)
    b = B()
    b.x is b  # evaluates to True
    c = my_deepcopy(a)  # works fine
    c = my_deepcopy(b)  # stack overflow, recurses forever
    
    from copy import deepcopy
    c = deepcopy(b)  # this works because of the second, hidden, dict argument
    

    忽略第二个隐藏的 dict 参数。不要尝试使用它。

    【讨论】:

      【解决方案4】:

      这是我用来向自己解释这一点的快速插图:

      a = [1,2,3]
      memo = {}
      b = copy.deepcopy(a,memo)
      # now memo = {139907464678864: [1, 2, 3], 9357408: 1, 9357440: 2, 9357472: 3, 28258000: [1, 2, 3, [1, 2, 3]]}
      
      key = 139907464678864
      print(id(a) == key)               #True
      print(id(b) == key)               #False
      print(id(a) == id(memo[key]))     #False
      print(id(b) == id(memo[key]))     #True
      

      换句话说:

      memo[id_of_initial_object] = copy_of_initial_object
      

      【讨论】:

        猜你喜欢
        • 2017-05-02
        • 2010-11-29
        • 2023-04-07
        • 2011-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-24
        相关资源
        最近更新 更多