初始化超类的传统方式,在子类的实例中调用超类的__init__()方法。

但是传统的方法有两个问题,比如:

问题1:

 class MyBaseClass:
def __init__(self, value):
self.value = value class TimesTwo:
def __init__(self):
self.value *= 2 class PlusFive:
def __init__(self):
self.value += 5 class OneWay(MyBaseClass, TimesTwo, PlusFive):
def __init__(self,value):
MyBaseClass.__init__(self, value)
TimesTwo.__init__(self)
PlusFive.__init__(self) class AnotherWay(MyBaseClass, PlusFive, TimesTwo):
def __init__(self,value):
MyBaseClass.__init__(self, value)
TimesTwo.__init__(self)
PlusFive.__init__(self) foo = OneWay(5)
print('OneWay (5*2)+5=', foo.value)
foo = AnotherWay(5)
print('AnotherWay:', foo.value)

结果为:

【Python】使用super初始化超类-LMLPHP

从结果可以看出,即使改变了子类的继承顺序,调用的顺序并没有改变。

问题2:

如果子类继承自两个单独的超类,而那两个超类又继承自同一个公共基类,那么就构成了钻石型继承。

这种继承会使钻石顶端的公共基类多次执行__init__()方法,从而产生意外。

比如:

 class MyBaseClass:
def __init__(self, value):
self.value = value class TimesFive(MyBaseClass):
def __init__(self, value):
MyBaseClass.__init__(self, value)
self.value *= 2 class PlusTwo(MyBaseClass):
def __init__(self, value):
MyBaseClass.__init__(self, value)
self.value += 2 class ThisWay(TimesFive, PlusTwo):
def __init__(self, value):
TimesFive.__init__(self, value)
PlusTwo.__init__(self, value) foo = ThisWay(5)
print('Should be (5*5)+2 but is ', foo.value)

在调用PlusTwo.__init__()时候,又一次调用MyBaseClass.__init__()又一次把value变为5

以上两种问题都可以使用super解决,方法解析顺序mro(method resolution order),以标准的流程安排超类之间的初始化顺序。

比如这次用super初始化超类

 class MyBaseClass:
def __init__(self, value):
self.value = value class TimesFive(MyBaseClass):
def __init__(self, value):
super(TimesFive, self).__init__(value)
self.value *= 5 class PlusTwo(MyBaseClass):
def __init__(self, value):
super(PlusTwo, self).__init__(value)
self.value += 2 class GoodWay(TimesFive, PlusTwo):
def __init__(self, value):
super(GoodWay, self).__init__(value) foo = GoodWay(5)
print('Should be 5*(5+2) and is ', foo.value)

并且可以使用

print(GoodWay.mro())

来查看初始化顺序:

【Python】使用super初始化超类-LMLPHP

参考资料:Effective Python

05-11 02:19