如何深度复制具有包装功能的对象?

时间:2019-04-19 15:04:17

标签: python inheritance copy wrapper

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

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可以解决此问题,但是我想避免它,因为它看起来很hacky。

在我的真实情况下,包装有点复杂,所以我无法摆脱它。如果您除去包装纸,它将按预期工作。我认为包装后的功能有点像“定居”,但我不知道如何解释。

所以我的问题是2折: -为什么此代码无法按预期工作(2个输出为0)? -我该如何解决?

1 个答案:

答案 0 :(得分:1)

由于要使用second_container创建deepcopy,因此永远不会调用其__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时发生,而不是在{{1} }时间:

__init__

如果这不可行,那么还有很多其他可能性-例如,您可以将class ContainerParent(object): @property def show(self): return do_wrapping(self._show) @show.setter def show(self, shower): self._show = shower 设置为属性,并将var行移至其设置器中-但很难说会怎样最好,而又不了解您的实际代码。