Niklas R
Niklas R

Reputation: 16870

Create a copy of a subclass, recursively?

The class Event implements a function copyFrom(self, event) and copy(self). The implementation of both methods is simple made cake.

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)

Now, the subclass MouseEvent wants to override both of them. The first method, copyFrom(self, event) can be implemented by calling the 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

But what about copy(self) ? Of course, just creating a new object is not hard.

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

But what if the Event class owns some private attributes ? The person that wants to subclass it, does not want to care about them !

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

This implementation of copy(self) looks quite dirty now, and so does the overriden one from MouseEvent.

class MouseEvent(Event):

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

How can I implement an easy, maybe recursive, copy-behaviour in this particular example ?

Upvotes: 1

Views: 562

Answers (1)

Sven Marnach
Sven Marnach

Reputation: 601569

First, isn't it enough that the MouseEvent constructor recursively calls the Event constructor?

If not, have a look at the copy module. It is based on pickle's state retrieval and restoration protocol. Using this protocol, recursive calls are easy. You could of course just copy this basic design if you don't want to conform to the pickle interface, by I don't see any advantage to doing so.

Edit: It seems I failed to get across the message, and indeed my answer might be a bit vague. So here we go with a code example using the suggested design:

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)

Note that you wouldn't even need the copy() and copy_from() methods if you would simply rename retrieve_state() and restore_state() to __getstate__() and __setstate__(), respectively, because after toding this you can just use the standard copy() module. (And in the case at hand, you wouldn't even need to define __getstate__() and __setstate__() at all, since the default behaviour is to save and restore all instance attributes.)

Upvotes: 3

Related Questions