Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: is there a use case for changing an instance's class?

Tags:

python

object

Related: Python object conversion

I recently learned that Python allows you to change an instance's class like so:

class Robe:
    pass

class Dress:
    pass

r = Robe()
r.__class__ = Dress

I'm trying to figure out whether there is a case where 'transmuting' an object like this can be useful. I've messed around with this in IDLE, and one thing I've noticed is that assigning a different class doesn't call the new class's __init__ method, though this can be done explicitly if needed.

Virtually every use case I can think of would be better served by composition, but I'm a coding newb so what do I know. ;)

like image 377
henrebotha Avatar asked Apr 06 '13 20:04

henrebotha


1 Answers

There is rarely a good reason to do this for unrelated classes, like Robe and Dress in your example. Without a bit of work, it's hard to ensure that the object you get in the end is in a sane state.

However, it can be useful when inheriting from a base class, if you want to use a non-standard factory function or constructor to build the base object. Here's an example:

class Base(object):
    pass

def base_factory():
    return Base()  # in real code, this would probably be something opaque

def Derived(Base):
    def __new__(cls):
        self = base_factory()     # get an instance of Base
        self.__class__ = Derived  # and turn it into an instance of Derived
        return self

In this example, the Derived class's __new__ method wants to construct its object using the base_factory method which returns an instance of the Base class. Often this sort of factory is in a library somewhere, and you can't know for certain how it's making the object (you can't just call Base() or super(Derived, cls).__new__(cls) yourself to get the same result).

The instance's __class__ attribute is rewritten so that the result of calling Derived.__new__ will be an instance of the Derived class, which ensures that it will have the Derived.__init__ method called on it (if such a method exists).

like image 165
Blckknght Avatar answered Sep 20 '22 04:09

Blckknght