是否以惯用方式将BaseClass对象转换为SubClass对象?

mik*_*iku 9 python inheritance subclass class-method

有一个基类Base和一个子类Special.

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
Run Code Online (Sandbox Code Playgroud)

如何将实例Base转换为实例Special?目前我已classmethod定义Special了仅仅重新确定__dict__:

class Special(Base):
    ...
    @classmethod
    def from_base(cls, baseobj):
        special = Special()
        special.__dict__ = baseobj.__dict__
        return special
Run Code Online (Sandbox Code Playgroud)

这是惯用的吗?如果不是会是什么?

PS示例场景:基类是一些默认实现.在野外,您可能会找到基类的对象.现在在某个项目中,基类已经是子类,并且已经在子类中添加了特殊方法.现在你仍然主要使用基类对象,但有时你会想要"升级"到特殊类,因为你需要访问一些方法.

Fas*_*tle 7

您可以通过定义备用构造函数并重新分配实例的__class__属性来实现此目的.

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?
Run Code Online (Sandbox Code Playgroud)

编辑:

将构造函数Special移至Base.

如果你不能修改Base类,你可以添加一个类方法,Special这将改变传递给它的任何对象的类.

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'>
Run Code Online (Sandbox Code Playgroud)

一个更通用的解决方案是创建一个可以添加到任何类的mixin.

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'>
Run Code Online (Sandbox Code Playgroud)