python單繼承與多繼承


一、單繼承

子類調用父類的一個方法,可以用super():

class A(object):
    def pp(self):
      print('pp A')

class B(A):
    def pp(self):
      super().pp()
      print("pp B")

b = B()
b.pp()

#結果:
pp A
pp B

super()常用的方法是在__init__()方法中確保父類被正確的初始化了:

super(cls,inst).__init__() #cls,init 可以省略

class A(object):
    def __init__(self):
      self.x = 1

class B(A):
    def __init__(self):
      super(B,self).__init__()
      self.x = self.x +1
      print(self.x)

b = B()

#結果
2

 

也可以直接調用父類的一個方法 :

A.__init__(self)
class A(object):
    def __init__(self):
        self.x = 1

class B(A):
    def __init__(self):
        A.__init__(self)
        self.x = self.x +1
        print(self.x)
b = B()

#結果
2                    

 

二、多繼承

super().xx方法可以理解為調用了父類中的方法xx,但是其實在單繼承中是這樣,而多繼承中有些區別

如下:

class A(object):
    def __init__(self):
        print("Enter A")

class B(A):
    def __init__(self):
        print('Enter B')
        super(B,self).__init__()
        print('Leave B')

class C(A):
    def __init__(self):
        print('Enter C')
        super(C, self).__init__()
        print('Leave C')

class D(B,C):
    def __init__(self):
        print('Enter D')
        super(D,self).__init__()
        print("Leave D")

d = D()
結果為:

Enter D
Enter B
Enter C
Enter A
Leave C
Leave B
Leave D                                            

 

如果按照原本的理解,是調用了B,C類中的方法,結果不會是這樣,那么為什么會這樣呢?

其實是我們理解錯了super()

super()的用法:

1.super()的本質

  先說說python中如何實現繼承---------對於你定義的每一個類,Python會計算出一個所謂的方法解析順序(MRO)列表。 這個MRO列表就是一個簡單的所有基類的線性順序表。為了實現繼承,Python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。

而這個MRO列表的構造是通過一個C3線性化算法來實現的。 我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條准則:

子類會先於父類被檢查
多個父類會根據它們在列表中的順序被檢查
如果對下一個類存在兩個合法的選擇,選擇第一個父類
雖然名義上來說super是用來調用父類中的方法,但是super實際上是在MRO表中找到下一個匹配的類。super原型如下:

def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
兩個參數 cls 和 inst 分別做了兩件事:
1. inst 負責生成 MRO 的 list
2. 通過 cls 定位當前 MRO 中的 index, 並返回 mro[index + 1]

但是根據我們上面說的super本質知道 super 和父類其實沒有實質關聯,我們就不難理解為什么 enter B 下一句是 enter C 而不是 enter A了(如果認為 super 代表“調用父類的方法”,會想當然的認為下一句應該是enter A)。

可以用  self.__class__.__mro__ 方法來查詢當前MRO

MRO:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
在我的理解里,一個多繼承中的ORM是固定的(只要每個類之間都有繼承關系)

上方例子的中流程:

首先是class D中,輸出“Enter D" , 然后就會調用super方法,super()方法,第一個參數是D,在MRO列表中的下標(index)為0,那么調用的下一個類就是下標為(index+1)的類,即class B,

那么進入class B,輸出"Enter B" ,再次調用super(),此時的index為1,那么調用的下一個類的index為2,即class C,輸出“Enter C” , 然后在class C中,調用super(),進入class A,輸出“Enter A”,然后回到class C ,輸出 "Leave C" , 再回到class B ,輸出“Leave B”, 然后回到class D,輸出“Leave D”。結束

 

當你使用 super() 函數時,Python會在MRO列表上繼續搜索下一個類。 只要每個重定義的方法統一使用 super() 並只調用它一次, 那么控制流最終會遍歷完整個MRO列表,每個方法也只會被調用一次。


免責聲明!

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



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