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) 。)