初始化超類的傳統方式,在子類的實例中調用超類的__init__()方法。
但是傳統的方法有兩個問題,比如:
問題1:
1 class MyBaseClass: 2 def __init__(self, value): 3 self.value = value 4 5 6 class TimesTwo: 7 def __init__(self): 8 self.value *= 2 9 10 11 class PlusFive: 12 def __init__(self): 13 self.value += 5 14 15 16 class OneWay(MyBaseClass, TimesTwo, PlusFive): 17 def __init__(self,value): 18 MyBaseClass.__init__(self, value) 19 TimesTwo.__init__(self) 20 PlusFive.__init__(self) 21 22 23 class AnotherWay(MyBaseClass, PlusFive, TimesTwo): 24 def __init__(self,value): 25 MyBaseClass.__init__(self, value) 26 TimesTwo.__init__(self) 27 PlusFive.__init__(self) 28 29 foo = OneWay(5) 30 print('OneWay (5*2)+5=', foo.value) 31 foo = AnotherWay(5) 32 print('AnotherWay:', foo.value)
結果為:
從結果可以看出,即使改變了子類的繼承順序,調用的順序並沒有改變。
問題2:
如果子類繼承自兩個單獨的超類,而那兩個超類又繼承自同一個公共基類,那么就構成了鑽石型繼承。
這種繼承會使鑽石頂端的公共基類多次執行__init__()方法,從而產生意外。
比如:
1 class MyBaseClass: 2 def __init__(self, value): 3 self.value = value 4 5 6 class TimesFive(MyBaseClass): 7 def __init__(self, value): 8 MyBaseClass.__init__(self, value) 9 self.value *= 2 10 11 12 class PlusTwo(MyBaseClass): 13 def __init__(self, value): 14 MyBaseClass.__init__(self, value) 15 self.value += 2 16 17 18 class ThisWay(TimesFive, PlusTwo): 19 def __init__(self, value): 20 TimesFive.__init__(self, value) 21 PlusTwo.__init__(self, value) 22 23 24 25 foo = ThisWay(5) 26 print('Should be (5*5)+2 but is ', foo.value)
在調用PlusTwo.__init__()時候,又一次調用MyBaseClass.__init__()又一次把value變為5
以上兩種問題都可以使用super解決,方法解析順序mro(method resolution order),以標准的流程安排超類之間的初始化順序。
比如這次用super初始化超類
1 class MyBaseClass: 2 def __init__(self, value): 3 self.value = value 4 5 6 class TimesFive(MyBaseClass): 7 def __init__(self, value): 8 super(TimesFive, self).__init__(value) 9 self.value *= 5 10 11 12 class PlusTwo(MyBaseClass): 13 def __init__(self, value): 14 super(PlusTwo, self).__init__(value) 15 self.value += 2 16 17 18 class GoodWay(TimesFive, PlusTwo): 19 def __init__(self, value): 20 super(GoodWay, self).__init__(value) 21 22 23 foo = GoodWay(5) 24 print('Should be 5*(5+2) and is ', foo.value)
並且可以使用
print(GoodWay.mro())
來查看初始化順序:
參考資料:Effective Python