我想使用Mixin总是为我的子类添加一些init功能,每个类继承自不同的API基类 . 具体来说,我想创建多个不同的子类,这些子类继承自这些不同的API提供的基类之一,以及一个Mixin,它将始终以相同的方式执行Mixin初始化代码,而无需代码复制 . 但是,看起来Mixin类的__init__函数永远不会被调用,除非我在Child类的__init__函数中明确地调用它,这不太理想 . 我 Build 了一个简单的测试用例:
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时有一个init函数)而不编写每个子类来显式调用Mixin的init函数? (即,不必在每个 class 做这样的事:)
class MixedClass(MyClass, SomeMixin):
def __init__(*args, **kwargs):
SomeMixin.__init__(self, *args, **kwargs)
MyClass.__init__(self, *args, **kwargs)
顺便说一下,如果我所有的子类都继承自相同的基类,我意识到我可以创建一个继承自基类和mixin的新中间类,并保持干燥 . 但是,它们从具有共同功能的不同基类继承 . (准确地说是Django Field类) .
3 回答
Python不会对类' super-class(es)—but it'的
__init__
方法执行任何隐式调用,以使其自动发生 . 一种方法是为混合类定义一个元类,它创建或扩展混合类'__init__
方法,以便按列出的顺序调用所有列出的基数'__init__
函数 .第二种方法是使用类装饰器 - 如下面的 Edit 部分所示 .
使用元类:
输出:
Edit
以下是如何使用类装饰器完成相同的操作(需要Python 2.6):
Notes
对于Python <2.6,请在类定义后使用
MixedClass = mixedomatic(MixedClass)
.在Python 3中,指定元类的语法是不同的,因此不是:
如上所示,您需要使用:
类装饰器版本将在两个版本中按原样运行 .
让基类调用
super().__init__()
,即使它是object
的子类 . 这样,所有__init__()
方法都将运行 .对不起,我这么晚才看到这个,但是
@Ignacio所说的模式被称为合作多重继承,它对合作感兴趣,使它成为第二个基础,并且你的第一个混合 . 在Python的MRO之后,将在基类之前检查mixin的
__init__()
(及其定义的任何其他内容) .这应解决一般性问题,但我不确定它是否能够处理您的具体用途 . 具有自定义元类(如Django模型)或奇怪装饰器(如@ martineau的答案;)的基类可以做疯狂的事情 .