python super() 作用和原理


python 在類的繼承中,當前類中如果方法與基類(父類)的方法一樣,會覆蓋基類的方法。

class Base(object):
    def run(self):
        print("Base start running~~")


class Dog(Base):
    def run(self):
        print("Dog start running~~")


if __name__ == "__main__":
    Dog().run()

# 結果
Dog start running~~

Process finished with exit code 0

上面代碼代碼中,基類Base 並沒有執行,但是有些時候,定義基類就是把共同的代碼寫在一起,在調用當前方法是,我們基類中已經實現的公共部分。

類的繼承

  1. 經典類(classic class) 基類名.方法名(self, *args, **kwargs), python版本低於2.2
  2. 新式類(new-style class) super(當前類名, self).方法名(*args, **kwargs), python 版本大於2.2
 1 class Base(object):
 2     def run(self):
 3         print("Now start running~~")
 4 
 5 class Dog(Base):
 6     def run(self):
 7         Base.run(self) # 經典類繼承
 8         print("Dog start running~~")
 9 
10 if __name__ == "__main__":
11     Dog().run()
12 
13 # 結果
14 Now start running~~
15 Dog start running~~
16 
17 Process finished with exit code 0

當使用經典類繼承時,Dog->Base->object 這種簡單的繼承順序還可以,如果出現多重繼承時,就會有下面的結果:

 1 class Base(object):
 2     def __init__(self):
 3         print("進入Base 類")
 4 
 5 
 6 class A(Base):
 7     def __init__(self):
 8         print("進入A 類")
 9         Base.__init__(self)
10 
11 
12 class B(Base):
13     def __init__(self):
14         print("進入B 類")
15         Base.__init__(self)
16 
17 
18 class C(A, B):
19     def __init__(self):
20         print("進入C 類")
21         A.__init__(self)
22         B.__init__(self)
23 
24 
25 if __name__ == "__main__":
26     c = C()

運行結果:

1 進入C 類
2 進入A 類
3 進入Base 類
4 進入B 類
5 進入Base 類
6 
7 Process finished with exit code 0

我們不難發現,執行順序: C -> A -> Base -> B -> Base

是不是順序有點蒙,我們理想狀態的順序難道不應該是: C -> A -> B -> Base (在繼承多個類時,繼承順序從左往右依次繼承)

如果按照理想狀態運行應該怎么辦, 我們就要用到 super 了。

super() 使用:

 1 class Base(object):
 2     def __init__(self):
 3         print("進入Base 類")
 4 
 5 
 6 class A(Base):
 7     def __init__(self):
 8         print("進入A 類")
 9         super(A, self).__init__()  # python2.7 的寫法
10 
11 
12 class B(Base):
13     def __init__(self):
14         print("進入B 類")
15         super().__init__()
16 
17 
18 class C(A, B):
19     def __init__(self):
20         print("進入C 類")
21         super().__init__()  # python3 繼承的寫法
22 
23 
24 if __name__ == "__main__":
25     c = C()

結果:

1 進入C 類
2 進入A 類
3 進入B 類
4 進入Base 類
5 
6 Process finished with exit code 0

這樣是不是就跟我們預想的一致了。

下面簡單說一下super 是怎么運行的:

MRO 

簡單說一下 MRO(Method Resolution Order),中文可以叫做 方法解析順序,  在方法調用時,需要對當前類以及基類進行搜索確定方法位置。

在程序中可以使用:

 print(C.mro()) 

結果:

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

python MRO

  • 經典類的深度遍歷
  • python2 新式類的預計算
  • python3 新式類的C3線性化計算

python3 統一使用 C3 線性化算法,有興趣的可以自行搜索。

小結

  • 在super機制里可以保證公共父類僅被執行一次
  • 執行的順序,是按照MRO:方法解析順序 進行的,執行完當前類按照mro 順序執行下個類。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM