递归复制子类?

1 投票
1 回答
555 浏览
提问于 2025-04-17 06:42

这个类叫做 Event,里面有两个功能,一个是 copyFrom(self, event),另一个是 copy(self)。这两个功能的实现其实很简单,就像做蛋糕一样容易。

class Event(object):

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def copyFrom(self, event):
        self.a = event.a
        self.b = event.b

    def copy(self):
        return Event(self.a, self.b)

现在,子类 MouseEvent 想要重写这两个功能。第一个功能 copyFrom(self, event) 可以通过调用父类的方法来实现。

class MouseEvent(Event):

    def __init__(self, a, b, c, d):
        super(Event, self).__init__(a, b)
        self.c = c
        self.d = d

    def copyFrom(self, event):
        super(Event, self).copyFrom(event)
        self.c = event.c
        self.d = event.d

但是 copy(self) 呢?当然,创建一个新对象并不难。

    # ...
    def copy(self):
        return MouseEvent(self.a, self.b, self.c, self.d)

但如果 Event 类里面有一些 私有 属性呢?想要继承这个类的人可不想去管这些私有属性!

class Event(object):

    def __init__(self, a, b):
        self.a = a
        self.b = b
        self._aab = fancyFunction(a, b)

    def doStuff(self, c):
        self._aab <<= c * 2

    def copyFrom(self, event):
        self.a = event.a
        self.b = event.b
        self._aab = event._aab

    def copy(self):
        e = Event(self.a, self.b)
        e._aab = self._aab
        return e

现在这个 copy(self) 的实现看起来就有点麻烦了,MouseEvent 重写的那个也是一样。

class MouseEvent(Event):

    # ...
    def copy(self):
        e = MouseEvent(self.a, self.b, self.c, self.d)
        e._aab = self._aab
        return e

在这个例子中,我该如何实现一个简单的,可能是递归的 复制 行为呢?

1 个回答

3

首先,MouseEvent的构造函数调用了Event的构造函数,这样就够了吗?

如果不够的话,可以看看copy模块。这个模块是基于pickle的状态获取和恢复协议。通过这个协议,递归调用变得很简单。当然,如果你不想遵循pickle的接口,你可以直接复制这个基本设计,但我觉得这样做没有什么好处。

编辑:看来我没有把我的意思表达清楚,我的回答可能有点模糊。所以这里有一个使用建议设计的代码示例:

class Event(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self._aab = fancyFunction(a, b)
    def retrieve_state(self):
        return self.a, self.b, self._aab
    def restore_state(self, state):
        self.a, self.b, self._aab = state
    def copy_from(self, event):
        self.restore_state(event.retrieve_state())
    def copy(self):
        e = object.__new__(self.__class__)
        e.restore_state(self.retrieve_state())
        return e

class MouseEvent(Event):    
    def __init__(self, a, b, c, d):
        Event.__init__(self, a, b)
        self.c = c
        self.d = d
    def retrieve_state(self):
        event_state = super(MouseEvent, self).retrieve_state()
        return event_state, self.c, self.d
    def restore_state(self, state):
        event_state, self.c, self.d = state
        super(MouseEvent, self).restore_state(event_state)

注意,如果你把retrieve_state()restore_state()分别改名为__getstate__()__setstate__(),你甚至不需要copy()copy_from()这两个方法,因为这样一来你就可以直接使用标准的copy()模块了。(在这个情况下,你甚至不需要定义__getstate__()__setstate__(),因为默认情况下会保存和恢复所有实例属性。)

撰写回答