Mixin类__init__函数不会自动调用吗?
我想使用Mixin来总是添加一些初始化function到我的子类,每个类都从不同的API基类inheritance。 具体来说,我想创build多个不同的子类,从这些不同的API提供的基类之一inheritance,以及一个Mixin,它将始终以相同的方式执行Mixin初始化代码,而无需代码复制。 但是,似乎Mixin类的__init__函数永远不会被调用,除非我们在Child类的__init__函数中明确地调用它,这是不太理想的。 我已经build立了一个简单的testing用例:
class APIBaseClassOne(object): def __init__(self, *args, **kwargs): print (" base ") class SomeMixin(object): def __init__(self, *args, **kwargs): print (" mixin before ") super(SomeMixin, self).__init__(*args, **kwargs) print (" mixin after ") class MyClass(APIBaseClassOne): pass class MixedClass(MyClass, SomeMixin): pass
正如你在下面的输出中看到的,Mixin函数的init永远不会被调用:
>>> import test >>> test.MixedClass() base <test.MixedClass object at 0x1004cc850>
有没有办法做到这一点(在调用Mixin中有一个初始化函数),而不写每个子类来显式调用Mixin的init函数? (即,不必在每个class级都做这样的事情:)
class MixedClass(MyClass, SomeMixin): def __init__(*args, **kwargs): SomeMixin.__init__(self, *args, **kwargs) MyClass.__init__(self, *args, **kwargs)
顺便说一句,如果我所有的子类都是从同一个基类inheritance的,我意识到我可以创build一个新的从基类和mixininheritance的中间类,并保持干的那种方式。 但是,它们从具有通用function的不同基类inheritance而来。 (准确地说,Django Field类)。
对不起,我看到这么晚了,但是
class MixedClass2(SomeMixin, MyClass): pass >>> m = MixedClass2() mixin before base mixin after
@Ignacio所说的模式称为协作式多重inheritance,这很好。 但是如果一个基类对合作不感兴趣,就把它作为第二个基础,然后把它放在第一个基础上。 mixin的__init__()
(以及它定义的其他东西)将在Python的MRO之后在基类之前被检查。
这应该解决一般问题,但我不确定它处理您的具体使用。 使用自定义元类(如Django模型)或奇怪的装饰器(如@ martineau的答案)的基类可以做疯狂的事情。
让基类调用super().__init__()
,尽pipe它是object
的子类。 这样所有的__init__()
方法都会运行。
class BaseClassOne(object): def __init__(self, *args, **kwargs): super(BaseClassOne, self).__init__(*args, **kwargs) print (" base ")
Python不会对类的超类的__init__
方法进行隐式调用 – 但可以自动实现。 一种方法是为混合类定义一个元类来创build或扩展混合类的__init__
方法,以便按列出的顺序调用所有列出的基类的__init__
函数。
第二种方法是使用一个类装饰器,在下面的部分标题编辑 。
使用元类:
class APIBaseClassOne(object): # API class (can't be changed) def __init__(self, *args, **kwargs): print ' APIBaseClassOne.__init__()' class SomeMixin(object): def __init__(self, *args, **kwargs): print ' SomeMixin.__init__()' class MixedClassMeta(type): def __new__(cls, name, bases, classdict): classinit = classdict.get('__init__') # Possibly None. # define an __init__ function for the new class def __init__(self, *args, **kwargs): # call the __init__ functions of all the bases for base in type(self).__bases__: base.__init__(self, *args, **kwargs) # also call any __init__ function that was in the new class if classinit: classinit(self, *args, **kwargs) # add the local function to the new class classdict['__init__'] = __init__ return type.__new__(cls, name, bases, classdict) class MixedClass(APIBaseClassOne, SomeMixin): __metaclass__ = MixedClassMeta # important # if exists, is called after the __init__'s of all the direct bases def __init__(self, *args, **kwargs): print ' MixedClass.__init__()' print('MixedClass():') MixedClass()
输出:
MixedClass(): APIBaseClassOne.__init__() SomeMixin.__init__() MixedClass.__init__()
编辑
以下是如何用类装饰器完成相同的事情(需要Python 2.6+):
class APIBaseClassOne(object): # API class (can't be changed) def __init__(self, *args, **kwargs): print)' APIBaseClassOne.__init__()') class SomeMixin(object): def __init__(self, *args, **kwargs): print(' SomeMixin.__init__()') def mixedomatic(cls): """ Mixed-in class decorator. """ classinit = cls.__dict__.get('__init__') # Possibly None. # define an __init__ function for the class def __init__(self, *args, **kwargs): # call the __init__ functions of all the bases for base in cls.__bases__: base.__init__(self, *args, **kwargs) # also call any __init__ function that was in the class if classinit: classinit(self, *args, **kwargs) # make the local function the class's __init__ setattr(cls, '__init__', __init__) return cls @mixedomatic class MixedClass(APIBaseClassOne, SomeMixin): # if exists, is called after the __init__'s of all the direct base classes def __init__(self, *args, **kwargs): print(' MixedClass.__init__()') print('MixedClass():') MixedClass()
(对于Python <2.6,请在类定义之后使用MixedClass = mixedomatic(MixedClass)
。)