如何深度复制具有包装函数的对象?

How can I deep copy an object which has a wrapped function?

所以我遇到了这个问题,我不明白一个变量以不同的方式显示,具体取决于我在容器中使用的函数,将它作为一个属性。我设法将其归结为以下代码:

import copy
from functools import wraps


def do_wrapping(func):
    @wraps(func)
    def wrapper(*args):
        return func(*args)
    return wrapper


class Container:
    def __init__(self, var):
        self.var = var
        self.show = self._show_method

    @property
    def show(self):
        return self._show

    @show.setter
    def show(self, shower):
        self._show = do_wrapping(shower)

    def _show_method(self):
        print(self.var)

first_container = Container(1)
second_container = copy.deepcopy(first_container)
second_container.var = 0
second_container.show()
second_container._show_method()

我希望这两种方法都能打印出 0,但第一种方法打印出 1。 使用这一行 second_container.show = second_container._show_method 解决了这个问题,但我想避免它,因为它看起来很老套。

在我的真实情况下,包装有点复杂,所以我无法摆脱它。如果您移除包装,它会按预期工作。我假设包装后,函数有点像 "set in stone" 但我不知道如何解释它。

所以我的问题有两个: - 为什么这段代码没有按预期工作(2 个输出是 0)? - 我该如何解决?

因为您正在使用 deepcopy 创建 second_container,它的 __init__ 方法永远不会被调用,所以它的 _show 属性是从 first_container 复制的秒。由于 first_container._show 是一个包装 first_container._show_method 的函数,这就是您调用 second_container.show()

时得到的结果

对于您的简单示例,您可以只调用 second_container.__init__(0) 而不是 second_container.var = 0。这有点不寻常,但它可能适用于您的实际代码。

如果您不能调用复制对象的 __init__ 方法,我认为我的首选方法是在调用 show getter 时进行函数包装,而不是比 __init__ 时间:

class ContainerParent(object):
    @property
    def show(self):
        return do_wrapping(self._show)

    @show.setter
    def show(self, shower):
        self._show = shower

如果那不可行,好吧,还有很多其他可能性 - 例如,您可以将 var 设为 属性 并将 self.show = self._show_method 行移动到其 setter - 但如果不了解您的实际代码,很难说什么是最好的。