Python類分為兩種,一種叫經典類,一種叫新式類。都支持多繼承,但繼承順序不同。
- 新式類:從object繼承來的類。(如:class A(object)),采用廣度優先搜索的方式繼承(即先水平搜索,再向上搜索)。
- 經典類:不從object繼承來的類。(如:class A()),采用深度優先搜索的方式繼承(即先深入繼承樹的左側,再返回,再找右側)。
1、普通繼承
子類中調用父類方法并不難,下面是一個簡單示例
class A:def __init__(self):self.attr_a = 1print('執行A的初始化函數')class B(A):def __init__(self):A.__init__(self)self.attr_b = 2b = B()
print(b.attr_a, b.attr_b)
輸出結果:
執行A的初始化函數
1 2
?2. 菱形繼承
在子類中直接調用父類的方法雖然可行,但在特定場景下會有問題,比如菱形繼承
class A:def __init__(self):self.attr_a = 1print('執行A的初始化函數')class B(A):def __init__(self):A.__init__(self)self.attr_b = 2print('執行B的初始化函數')class C(A):def __init__(self):A.__init__(self)self.attr_c = 3print('執行C的初始化函數')class D(B, C):def __init__(self):B.__init__(self)C.__init__(self)self.attr_d = 4print('執行D的初始化函數')d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
A是B和C的父類,D同時繼承了B和C, 這樣就形成了菱形繼承,所謂菱形繼承,僅僅是因形狀上像菱形。程序執行結果
執行A的初始化函數
執行B的初始化函數
執行A的初始化函數
執行C的初始化函數
執行D的初始化函數
1 2 3 4
應該注意到,類A的初始化函數被執行了兩次,這是一個非常危險的行為,如果A的初始化函數執行了一些一個進程中只能執行一次的代碼,這樣的多進程就會導致嚴重的問題, super的引入就是為了解決這種問題。
class A:def __init__(self):self.attr_a = 1print('執行A的初始化函數')class B(A):def __init__(self):super().__init__()self.attr_b = 2print('執行B的初始化函數')class C(A):def __init__(self):super().__init__()self.attr_c = 3print('執行C的初始化函數')class D(B, C):def __init__(self):super().__init__()self.attr_d = 4print('執行D的初始化函數')d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
執行結果
執行A的初始化函數
執行C的初始化函數
執行B的初始化函數
執行D的初始化函數
1 2 3 4
在D的初始化函數中,只使用了一行代碼super().__init__(), 就將兩個父類B和C的初始化函數都執行了, 而且不會重復執行A的初始化函數,這些都是super幫助我們完成的。?
3. MRO
在第2小結的示例中, 執行D的初始化函數,使用了super,會自動執行B,C的初始化函數,那么B與C的初始化函數先執行哪個呢?對于這個問題,在我們定義類時,python會計算出一個方法解析順序列表,也就是MRO,這個MRO列表就是一個簡單的所有基類的線性順序表, 類的mro()方法可以獲得MRO
print(D.mro())
輸出結果
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
按照順序,先執行B的初始化函數,在執行C的初始化函數,最后執行A的初始化函數。
4. 帶參數的super方法使用示例
為了簡化代碼,前面的示例代碼在執行super方法時,都沒有使用任何參數,下面提供了有參數的示例
class A:def __init__(self):self.attr_a = 1def add(self, a, b):return a + bclass B(A):def __init__(self):super().__init__()self.attr_b = 2def add(self, a, b):print('執行B的add')return a + b + 1class C(A):def __init__(self):super().__init__()self.attr_c = 3def add(self, a, b):print('執行C的add')return a + b + 2class D(B, C):def __init__(self):super().__init__()self.attr_d = 4def add(self, a, b):return super().add(a, b)d = D()
print(d.add(1, 2))
程序執行結果
執行B的add
4
D的父類B和C都有add方法,在D的add方法時,super().add()會根據mro來決定調用哪個父類的add方法,根據順序,應該執行B的add方法, 如果你希望執行C的add方法, 那么可以這樣來實現add方法
def add(self, a, b):return super(B, self).add(a, b)
在mro列表里,B的后面是C, super的第一個函數指定為B, 第二個參數設置為self,就會執行C的add方法。
引文:python面向對象--super() | 酷python