递归地创建子类的副本?

时间:2011-11-20 18:16:03

标签: python class copy

课程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)可以通过调用 super -method来实现。

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

如何在这个特定的例子中实现一个简单的,可能是递归的副本 -behaviour?

1 个答案:

答案 0 :(得分:3)

首先,MouseEvent构造函数递归调用Event构造函数是不够的?

如果没有,请查看copy module。它基于pickle's state retrieval and restoration protocol。使用此协议,递归调用很容易。如果你不想符合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)

请注意,如果您只需将copy()copy_from()重命名为retrieve_state()和{{1},则甚至不需要restore_state()__getstate__()方法分别是因为在编码之后你可以使用标准的__setstate__()模块。 (在手头的情况下,您根本不需要定义copy()__getstate__(),因为默认行为是保存和恢复所有实例属性。)