前言
??在python
繼承的時候經常會遇到super
這個東西,搞得不是太明白,寫下這篇博文記錄一下。我這里用的是python3
版本。
一. super是什么
先來看下super
是什么,怎么用的,具體后面介紹?
super
是一個內置函數(shù),用于調用父類(超類)的方法。它提供了一種方便的方式來調用父類的方法,而不需要顯式地指定父類的名稱。super
函數(shù)通常在子類的方法中使用。當你在子類中重寫一個方法時,可以使用super函數(shù)來調用父類的相同方法。這樣可以在不破壞繼承關系的前提下,擴展或修改父類的行為。super
函數(shù)接受兩個參數(shù):子類的類名和子類的實例,即super(子類類名,self).__init__()
它返回一個特殊的對象,該對象可以用于調用父類的方法。通過super
函數(shù)返回的對象,可以在子類中直接調用父類的方法,而無需顯式指定父類的名稱。在python3
中已經簡化了這種寫法:直接寫成super().__init__()
。
看個例子
class ParentClass:
def __init__(self):
self.parent_var = 10
def some_method(self):
print("ParentClass method")
class ChildClass(ParentClass):
def __init__(self):
super().__init__() # 調用父類的初始化方法
self.child_var = 20
def some_method(self):
super().some_method() # 調用父類的方法
print("ChildClass method")
child_obj = ChildClass()
child_obj.some_method()
把上面的代碼改成類名繼承看下:
class ParentClass:
def __init__(self):
self.parent_var = 10
def some_method(self):
print("ParentClass method")
class ChildClass(ParentClass):
def __init__(self):
ParentClass.__init__(self) # 調用父類的初始化方法
self.child_var = 20
def some_method(self):
ParentClass.some_method(self) # 調用父類的方法
print("ChildClass method")
child_obj = ChildClass()
child_obj.some_method()
輸出:
ParentClass method
ChildClass method
??通過對比可以看到通過super
可以直接替代類名從而簡便繼承方式。其實super
對于普通函數(shù)的繼承很好理解,就是直接通過super().xxx()
即可調用父類的方法。我們下面重點介紹下經常讓人困惑的super().__init__()
。
二.super().__ init__ ()
??在理解super().__ init__ ()
的時候也可以直接把他當做繼承普通的函數(shù)一樣,只不過這里是繼承父類的構造函數(shù)。既然是繼承父類的構造函數(shù),那么在繼承的時候同樣出現(xiàn)一種現(xiàn)象,那就是重寫(有些人叫覆蓋,個人感覺叫做重寫更嚴謹),重寫顧名思義就是父類已經有了這個函數(shù)了,子類中又寫了一遍。根據(jù)強龍不壓地頭蛇的原則,那么在使用的時候如果發(fā)生了重寫,就要以子類的函數(shù)為準??磦€例子:
class A:
def __init__(self):
print("調用A")
class B(A):
def __init__(self):
print("調用B")
b = B()
輸出:
調用B
??上面的代碼可以發(fā)現(xiàn),雖然B
繼承了A
,但是構造函數(shù)重寫了,所以在調用實例化B
的時候調用的還是B
本身的構造函數(shù),可以理解為父類的構造函數(shù)被覆蓋了。如果我還想調用父類的怎么辦呢,如果你能想到繼承,說明你基本上已經明白了,我們直接看例子:
class A:
def __init__(self):
print("調用A")
class B(A):
def __init__(self):
super().__init__()
print("調用B")
b = B()
輸出:
調用A
調用B
再來看個稍微復雜點的例子:
class ParentClass:
def __init__(self, x):
self.parent_var = x
def some_method(self):
print("ParentClass method")
class ChildClass(ParentClass):
def __init__(self, x, y):
super().__init__(x) # 繼承父類的構造函數(shù)
self.child_var = y
child_obj = ChildClass(10, 20)
print(child_obj.parent_var) # 訪問繼承的父類屬性
print(child_obj.child_var) # 訪問子類屬性
輸出:
10
20
子類中并沒有parent_var這個屬性,但是可以通過繼承父類的構造函數(shù)獲取到這個屬性。
三. 繼承順序
??當發(fā)生多繼承的時候他的順序是什么樣的,如下面的一段代碼C
這個子類在繼承父類的初始化函數(shù)的時候到底繼承的是A
的還是B
的?
class A:
def __init__(self):
print('A')
class B:
def __init__(self):
print('B')
class C(A, B):
def __init__(self):
print('C')
super().__init__()
c = C()
我們看一下輸出結果是什么:
C
A
??為什么輸出的是C
,A
呢?這里涉及到Python
中的菱形繼承。菱形繼承的原則是繼承的兩個父類時并列的。按照繼承的父類從左至右的順序查找的,如果在當前類中找到方法,就直接執(zhí)行,不再進行搜索,如果沒有找到就查找下一個繼承的父類中是否有對應的方法,如果找到,就直接執(zhí)行,不再搜索,如果找到最后一個類,還沒有找到方法,程序報錯。
根據(jù)上面的原則,我們來看一個復雜點的多繼承:
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super().__init__()
class C(A):
def __init__(self):
print('C')
super().__init__()
class D(A):
def __init__(self):
print('D')
super().__init__()
class E(B, C):
def __init__(self):
print('E')
super().__init__()
class F(C, D):
def __init__(self):
print('F')
super().__init__()
class G(E, F):
def __init__(self):
print('G')
super().__init__()
g = G()
輸出:
G
E
B
F
C
D
A
??根據(jù)輸出結果可以看到G
繼承自E
, F
是并列的,初始化的時候不會先把E
初始化完畢才初始化F
。也可以通過Python
自帶的__mro__
查看一下繼承順序:
print(G.__mro__)
輸出:文章來源:http://www.zghlxwxcb.cn/news/detail-732633.html
(<class '__main__.G'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
至此關于super
的基本介紹就已經講完了,如有錯誤,敬請指正!文章來源地址http://www.zghlxwxcb.cn/news/detail-732633.html
到了這里,關于python中super用法的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!