Skip to content Skip to sidebar Skip to footer

Convert A Baseclass Object Into A Subclass Object Idiomatically?

There is a base class Base and a subclass Special. class Base(object): def __init__(self, name): self.name = name def greet(self): return 'Hello %s' % self.

Solution 1:

You can achieve this by defining an alternate constructor and reassigning the instance's __class__ attribute.

classBase(object):def__init__(self, name):
        self.name = name

    defgreet(self):
        return'Hello %s' % self.name

    @classmethoddefalt_constructor(cls, *args, **kwargs):
        obj = cls(*args, **kwargs)
        obj.__class__ = Special
        return obj


classSpecial(Base):def__init__(self, name):
        super(Special, self).__init__(name)

    defrhyme(self):
        return'Hi %s! How are you? Fine, thanks. What about you?' % self.name


>>> s = Base.alt_constructor("test")
>>> print s.rhyme()
Hi test! How are you? Fine, thanks. What about you?

EDIT:

Moved the constructor from Special to Base.

If you can't modify the Base class you can add a classmethod to Special that will change the class of any object passed to it.

classBase(object):
    def__init__(self, name):
        self.name = name

    defgreet(self):
        return'Hello %s' % self.name


classSpecial(Base):
    def__init__(self, name):
        super(Special, self).__init__(name)

    defrhyme(self):
        return'Hi %s! How are you? Fine, thanks. What about you?' % self.name

    @classmethoddefconvert_to_special(cls, obj):
        obj.__class__ = Special

>>> b = Base("test")
>>> printtype(b)
<class'__main__.Base'>

>>> Special.convert_to_special(b)
>>> printtype(b)
<class'__main__.Special'>

A more all purpose solution would be to create a mixin that can be added to any class.

classConverterMixin(object):

    @classmethoddefconvert_to_class(cls, obj):
        obj.__class__ = cls


classSpecial(ConverterMixin, Base):
    def__init__(self, name):
        super(Special, self).__init__(name)

    defrhyme(self):
        return'Hi %s! How are you? Fine, thanks. What about you?' % self.name

>>> b = Base("test")
>>> printtype(b)
<class'__main__.Base'>

>>> Special.convert_to_class(b)
>>> printtype(b)
<class'__main__.Special'>

Solution 2:

actually you can, but I don't think you should. instead of typecasting python has duck-typing to solve this kind of situation.

anyway, here's the code:

>>>base = Base("I'm a base!")>>>hasattr(base, 'rhyme')
False
>>>base.__class__ = Special>>>hasattr(base, 'rhyme')
True
>>>base.rhyme()
"Hi I'm a base!! How are you? Fine, thanks. What about you?"

Post a Comment for "Convert A Baseclass Object Into A Subclass Object Idiomatically?"