创建具有嵌套的weakref的类实例的深层副本

创建具有嵌套的weakref的类实例的深层副本

本文介绍了创建具有嵌套的weakref的类实例的深层副本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类:父类和容器类。父类实例具有匹配的容器类实例作为弱引用。

I have two classes: a parent class and a container class. The parent class instance has matching container class instance as a weak reference.

深度复制父实例时出现问题,weakref仍链接到原始实例。这是一个最小的示例:

There is a problem while deep copying the parent instance, the weakref is still linking to the original instance. Here is a minimal example:

import weakref
from copy import deepcopy


class Container:
    def __init__(self, parent):
        self.parent = weakref.ref(parent)


class Parent:
    def __init__(self):
        self.container = Container(self)


if __name__ == '__main__':
    parent1 = Parent()
    assert(parent1 is parent1.container.parent())

    parent2 = deepcopy(parent1)
    assert(parent2 is parent2.container.parent())

第二个断言失败。

我怀疑 __ deepcopy __ 魔术方法可以实现,但不确定具体如何。

I suspect that the __deepcopy__ magic method can be implemented, but not sure how exactly.

推荐答案

问题是 deepcopy 将不会跟随 weakref.ref 链接。它甚至不会复制 weakref.ref

The problem is that deepcopy won't follow the weakref.ref link. It doesn't even copy the weakref.ref:

>>> from copy import deepcopy
>>> import weakref
>>>
>>> parent1 = Parent()
>>> ref1 = weakref.ref(parent1)
>>> ref2 = deepcopy(ref1)
>>> ref1 is ref2
True

即已明确硬编码 。我不知道为什么会这样,但是我怀疑他们有他们的原因。

That is explicitly hardcoded in the copy module. I don't know why this is but I suspect they had their reasons.

但是您可以实现 __ deepcopy __ 方法:

import weakref
from copy import deepcopy

class Container:
    def __init__(self, parent):
        self.parent = weakref.ref(parent)

class Parent:
    def __init__(self):
        self.container = Container(self)

    def __deepcopy__(self, memo):
        # set __deepcopy__ element to "false"-ey value so we don't go into
        # recusion.
        self.__deepcopy__ = None
        try:
            new = deepcopy(self, memo)
        finally:
            # Always delete the self.__deepcopy__ again, even if deepcopying failed
            del self.__deepcopy__
        del new.__deepcopy__  # remove the copied __deepcopy__ attribute
        new.container.parent = weakref.ref(new)
        return new

if __name__ == '__main__':
    parent1 = Parent()
    assert parent1 is parent1.container.parent()

    parent2 = deepcopy(parent1)
    assert parent2 is parent2.container.parent()

    parent3 = deepcopy(parent2)
    assert parent3 is parent3.container.parent()

由于临时的 __ deepcopy __ 实例属性,这有点难看。但是它允许在 self 上使用普通的 deepcopy 函数,而无需进行无限递归,那么您只需要手动创建

It's a bit ugly because of the temporary __deepcopy__ instance attribute. But it allows to use the normal deepcopy function on self without going into infinite recursions and then you only have to manually create a new weak reference to your parent.

您甚至可以在不临时设置 __ deepcopy __ 的情况下进行操作(它应该可以正常工作):

You could even do it without temporarily setting __deepcopy__ (it should work correctly):

import weakref
from copy import deepcopy

class Container:
    def __init__(self, parent):
        self.parent = weakref.ref(parent)

class Parent:
    def __init__(self):
        self.container = Container(self)

    def __deepcopy__(self, memo):
        # Create a new class
        new = object.__new__(type(self))
        memo[id(self)] = new   # add the new class to the memo
        # Insert a deepcopy of all instance attributes
        new.__dict__.update(deepcopy(self.__dict__, memo))
        # Manually update the weakref to be correct
        new.container.parent = weakref.ref(new)
        return new

if __name__ == '__main__':
    parent1 = Parent()
    assert parent1 is parent1.container.parent()

    parent2 = deepcopy(parent1)
    assert parent2 is parent2.container.parent()

    parent3 = deepcopy(parent2)
    assert parent3 is parent3.container.parent()

这篇关于创建具有嵌套的weakref的类实例的深层副本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 13:49