Convert a BaseClass object into a SubClass object idiomatically?

前端 未结 2 1853
终归单人心
终归单人心 2020-12-16 20:45

There is a base class Base and a subclass Special.

class Base(object):
    def __init__(self, name):
        self.name = name
    d         


        
相关标签:
2条回答
  • 2020-12-16 21:20

    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?"
    
    0 讨论(0)
  • 2020-12-16 21:35

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

    class Base(object):
        def __init__(self, name):
            self.name = name
    
        def greet(self):
            return 'Hello %s' % self.name
    
        @classmethod
        def alt_constructor(cls, *args, **kwargs):
            obj = cls(*args, **kwargs)
            obj.__class__ = Special
            return obj
    
    
    class Special(Base):
        def __init__(self, name):
            super(Special, self).__init__(name)
    
        def rhyme(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.

    class Base(object):
        def __init__(self, name):
            self.name = name
    
        def greet(self):
            return 'Hello %s' % self.name
    
    
    class Special(Base):
        def __init__(self, name):
            super(Special, self).__init__(name)
    
        def rhyme(self):
            return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name
    
        @classmethod
        def convert_to_special(cls, obj):
            obj.__class__ = Special
    
    >>> b = Base("test")
    >>> print type(b)
    <class '__main__.Base'>
    
    >>> Special.convert_to_special(b)
    >>> print type(b)
    <class '__main__.Special'>
    

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

    class ConverterMixin(object):
    
        @classmethod
        def convert_to_class(cls, obj):
            obj.__class__ = cls
    
    
    class Special(ConverterMixin, Base):
        def __init__(self, name):
            super(Special, self).__init__(name)
    
        def rhyme(self):
            return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name
    
    >>> b = Base("test")
    >>> print type(b)
    <class '__main__.Base'>
    
    >>> Special.convert_to_class(b)
    >>> print type(b)
    <class '__main__.Special'>
    
    0 讨论(0)
提交回复
热议问题