tags:

views:

60

answers:

4

Hi,
Is it possible to mutate an object into an instance of a derived class of the initial's object class? Something like:

class Base():
    def __init__(self):
        self.a = 1

    def mutate(self):
        self = Derived()

class Derived(Base):
    def __init__(self):
        self.b = 2

But that doesn't work.

>>> obj = Base()
>>> obj.mutate()
>>> obj.a
1
>>> obj.b
AttributeError...

If this isn't possible, how should I do otherwise?
My problem is the following: My Base class is like a "summary", and the Derived class is the "whole thing". Of course getting the "whole thing" is a bit expensive so working on summaries as long as it is possible is the point of having these two classes. But you should be able to get it if you want, and then there's no point in having the summary anymore, so every reference to the summary should now be (or contain, at least) the whole thing. I guess I would have to create a class that can hold both, right?

class Thing():
    def __init__(self):
        self.summary = Summary()
        self.whole = None

    def get_whole_thing(self):
        self.whole = Whole()
+4  A: 

A general OOP approach would be to make the summary object be a Façade that Delegates the expensive operations to a (dynamically constructed) back-end object. You could even make it totally transparent so that callers of the object don't see that there is anything going on (well, not unless they start timing things of course).

Donal Fellows
Note also that Façade and Delegate are both types of Software Pattern, which is why I capitalized them. If you've never encountered them before, now is a good time to learn.
Donal Fellows
Thanks for your answer. I finally did it another way because that is a simple class and that way I didn't need the multiple classes that the Delegate pattern needs. But I can see that it would be a good solution for a more complex case. Thanks!
Gohu
@Gohu: The Facade is the "Summary" over the collection of details. It's two classes. It's not complex at all. It's a simpler approach because you will correctly separate "Summary" from "Details".
S.Lott
A: 

I forgot to say that I also wanted to be able to create a "whole thing" from the start and not a summary if it wasn't needed. I've finally done it like that:

class Thing():
    def __init__(self, summary=False):
        if summary:
            self.summary = "summary"
            self._whole = None
        else:
            self._whole = "wholething"

    @property
    def whole(self):
        if self._whole: return self._whole
        else:
            self.__init__()
            return self._whole

Works like a charm :)

Gohu
A: 

You cannot assign to self to do what you want, but you can change the class of an object by assigning to self.class.

However this is really bad practice - for your situation delegation is better than inheritance.

Dave Kirby
+3  A: 

Responding to the original question as posed, changing the mutate method to:

def mutate(self):
    self.__class__ = Derived

will do exactly what was requested -- change self's class to be Derived instead of Base. This does not automatically execute Derived.__init__, but if that's desired it can be explicitly called (e.g. as self.__init__() as the second statement in the method).

Whether this is a good approach for the OP's actual problem is a completely different question than the original question, which was

Is it possible to mutate an object into an instance of a derived class of the initial's object class?

The answer to this is "yes, it's possible" (and it's done the way I just showed). "Is it the best approach for my specific application problem" is a different question than "is it possible";-)

Alex Martelli