Convert a BaseClass object into a SubClass object idiomatically?
有一个基类
1 2 3 4 5 6 7 8 9 10 11 | 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 |
如何将
1 2 3 4 5 6 7 | class Special(Base): ... @classmethod def from_base(cls, baseobj): special = Special() special.__dict__ = baseobj.__dict__ return special |
号
这是习语吗?如果不是,会是什么?
P.S.一个示例场景:基类是一些默认实现。在野外,您可能会找到基类的对象。现在,在一些项目中,基类是子类,并向子类添加了特殊的方法。现在您仍然主要使用基类对象,但有时您会希望"升级"到特殊类,因为您需要访问某些方法。
您可以通过定义一个备用构造函数并重新分配实例的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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? |
编辑:
将构造函数从
如果不能修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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'> |
号
一个更通用的解决方案是创建一个可以添加到任何类中的mixin。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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'> |
实际上你可以,但我认为你不应该。而不是打字,python有duck-typing来解决这种情况。
不管怎样,代码如下:
1 2 3 4 5 6 7 8 | >>> 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?" |
。