2015-10-19 65 views
0

我對python多繼承有點困惑。python多繼承超級函數

例如,如果你有:

class A(object): 
def __init__(self): 
    print "init A" 
    super(A, self).__init__() 

class B(A): 
    def __init__(self): 
     print "init B" 
     super(B, self).__init__() 

class C(A): 
    def __init__(self): 
     print "init C" 
     super(C, self).__init__() 

class D(C, B): 
    def __init__(self): 
     print "init D" 
     super(D, self).__init__() 

if __name__ == '__main__': 
    D() 

的方法解析順序(MRO)將D-C-B-A。

爲什麼順序不是d-C-A-B-A?

+0

因爲你不能在mro中有重複的東西... – Bakuriu

+0

的確,Python的繼承系統的整個設計是使鑽石繼承方案像你所展示的那樣。由於重複路徑到達最終基類,它們傾向於在其他語言(如C++)中做壞事。 – Blckknght

回答

1

你只實例化一個對象。 Python允許每個祖先的__init__在MRO中只執行一次。因此,我們沒有得到這兩個A-> C和A-> B關係,執行A.__init__

由於只有這麼多解釋,你可能會認爲我們會得到DCAB ...但由於B也需要A.__init__,則在確定執行順序之前,MRO有足夠的耐心解決整個圖形。

2

Python文檔:

有了新的樣式類,動態排序是必要的,因爲多重繼承展覽的一個或多個菱形關係(父類,其中至少一個所有病例可以通過多條路徑訪問來自最底層的課程)。例如,所有新樣式的類都從對象繼承,所以任何多繼承的情況都會提供多條路徑來達到對象。 爲了保持基類被訪問一次以上,動態算法線性化的方式搜索順序,保留在每類中指定的左到右的順序,即要求每個家長只有一次,那就是單調(這意味着一個類可以在不影響其父母的優先順序的情況下進行子類化)。綜合起來,這些屬性使設計具有多繼承性的可靠和可擴展的類成爲可能。有關更多詳細信息,請參見https://www.python.org/download/releases/2.3/mro/

1

粗略地說,MRO是通過將所有基底先深度優先,從左到右,然後刪除任何重複項,然後刪除最後一項來給出的。

的算法是這樣的,對於任何的基類,基類的MRO訂單將始終是相同的(如果這是不可能的,我相信你會得到一個錯誤)。

如果重複未刪除,則順序實際上是d-C-A-對象-B-A-對象。由於多種原因,這是令人困惑的。首先,如果方法調用super,就像你的情況一樣,那麼同樣的方法可以被調用兩次。其次,B的實現期望在A之前並且在方法解析順序中反對是合理的。如果它覆蓋了A的屬性,則不會預期這個覆蓋將被顛倒。

1

究其原因,是MRO d-C-B-A的是,它是d-C-A-B-A(或d-C-A-B)將具有奇怪的效果。在這個特殊的例子中,A類的構造函數沒有參數明確是否super()電話,只有在鑽石繼承樹事項。如果它沒有執行super調用,則不會從A構造函數調用B構造函數。如果構造函數有參數,那麼A的構造函數會卡在岩石和堅硬的地方之間。如果它不叫super那麼它不適用於鑽石繼承。如果它確實叫super那麼,因爲object.__init__沒有參數,所以構造函數會失敗,如果它沒有用於鑽石繼承模式。