2013-04-23 57 views
0

我有兩個多重繼承的例子看起來像相同,但我得到differents結果順序。Python的超級()爲多繼承不一致

First ExampleJoël

class A(object): 
    def t(self): 
     print 'from A' 

class B(object): 
    def t(self): 
     print 'from B' 

class C(A): pass 

class D(C, B): pass 

而作爲一個結果,我們已經:

>>> d = D() 
>>> d.t() # Will print "from A" 

>>> D.__mro__ 
(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.A'>, 
<class '__main__.B'>, <type 'object'>) 

然後Second ExampleCallisto

class First(object): 
    def __init__(self): 
     print "first" 

class Second(First): 
    def __init__(self): 
     print "second" 

class Third(First): 
    def __init__(self): 
     print "third" 

class Fourth(Second, Third): 
    def __init__(self): 
     super(Fourth, self).__init__() 
     print "that's it" 

而當我們」結果ve:

>>> f = Fourth() 
second 
that's it 

>>> Fourth.__mro__ 
(<class '__main__.Fourth'>, <class '__main__.Second'>, <class '__main__.Third'> 
<class '__main__.First'>, <type 'object'>) 

正如你所看到的,MRO流動順序是不同的,在第二個例子是Third之前沒有達到First,但在第一個例子是由A纔去B通過。

感謝

+0

什麼是你的問題? – Eric 2013-04-23 18:16:00

+0

@Eric:問題是:爲什麼在第二個例子中,它在第三個之前沒有達到第一個,但是在第一個例子中,在到達B之前,它經過了A? – 2013-04-23 18:18:40

+0

@segfolt:是的,如果你關注MRO,你會發現行爲(順序)是不同的,但代碼是相同的,在我看來,MRO ordem應該是相同的。 – 2013-04-23 18:21:05

回答

2

沒有矛盾。 MRO基於C3算法,該算法由Chaturvedi解釋,更正式地由Simionato解釋。


關於:

在第二個例子是不三之前先到達,但在 第一個例子是由A纔去B.

由於Third通定義爲

class Third(First): 

必須在MRO中的First之前出現。

維迪解釋這與規則,

如果A是B的超類,那麼B的優先級高於A.或者,乙方應 總是在所有__mro__個出現之前(含兩個) 。

雖然在第一示例中,FirstThird等效是AC。由於C

class C(A): 

C定義在MRO A之前。

爲什麼A之前B更復雜。最終歸因於CB之前以D爲基礎列出。在Simionato的符號,

L[D] = L[D(C,B)] = D + merge(L[C], L[B], CB) 
    = D + merge(CAO, BO, CB) 
    = D + C + merge(AO, BO, B) 
    = D + C + A + merge(O, BO, B) 
    = D + C + A + B + merge(O, O) 
    = D + C + A + B + O 

並且在第二示例中,

L[4] = L[4(2, 3)] = 4 + merge(L[2], L[3], 23) 
    = 4 + merge(21O, 31O, 23) 
    = 4 + 2 + merge(1O, 31O, 3) 
    = 4 + 2 + 3 + merge(1O, 1O) # Third must come before First 
    = 4 + 2 + 3 + 1 + merge(O, O) 
    = 4 + 2 + 3 + 1 + O 

operative rule感:

採取第一列表的頭部,即,L [B1] [0] ; 如果該頭不在其他任何列表的尾部,則將其添加到C的線性化 並將其從合併中的列表中刪除,否則查看下一個列表的 頭部並將其取出,如果它是一個好頭。然後重複 的操作,直到所有班級都被刪除或者不可能找到好頭。在這種情況下,構建 合併是不可能的,Python 2.3將拒絕創建類C,並且會引發一個 異常。

(我的重點解釋了爲什麼Third必須在First之前)。

+0

然後,在第二個例子中,如果在'2'類中沒有一個'__init__'指令,那麼會發生'4 - > 2 - > 3 - > 1' '所以它會在回溯到'4'之前嘗試'1'類? 我想我得到了,他們會做一些左遞歸直到達到指令或結束,然後跳到右兄弟參數。 – 2013-04-23 18:48:40

+0

對不起,但我很難跟隨你的要求。我建議閱讀[Chaturvedi](http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html)以瞭解算法的風格,並閱讀[Simionato](http://www.python.org/) 2.3/mro.html)的細節。然後參考我的帖子中的公式,我將顯示你的兩個例子的所有血統細節。 – unutbu 2013-04-23 18:57:16

+0

@unutbu:我正在閱讀Simionato的教程。在本教程中,我不明白過渡:'A + B +合併(DEO,CDFO,C)= A + B + C +合併(DEO,DFO)''。在我看來,由於操作規則,它應該是'= A + B + D +合併(EO,CFO,C)'。如果你能解釋過渡,我會非常感激。謝謝! – 2013-04-23 19:52:01

-1

你的第一個層次結構繼承看起來像這樣:

D 
|\ 
C B 
| | 
A | 
\| 
    object 

而第二個是:

4 
|\ 
2 3 
\| 
    1 
    | 
    object 

爲什麼在第二個例子中它不Third過,但在第一次到達First示例在去B之前通過A

爲什麼你會期望這些表現方式相同?縱觀圖表,AB之間的關係是完全不同的FirstThird

0

之間這是不一樣的,在第一個例子中,所有的「爸爸」對象繼承對象,作爲加載的d負荷Ç並且按照MRO,B的順序(由D調用)

其次,所有「父親」對象繼承了類First。此時,Python需要先處理第二個和第三個。 PS:這是我的理論,但它只是邏輯。

這裏是你在他的例子來實現什麼的運行例如:http://ideone.com/pfzXiG

class First(object): 
    def __init__(self): 
     print "first" 

class Second(First): 
    def __init__(self): 
     print "second" 

class Third(First): 
    def __init__(self): 
     print "third" 

class Fourth(Second, Third): 
    def __init__(self): 
     super(Fourth, self).__init__() 
     print "that's it" 

print "First: " 
print Fourth.__mro__ 

class First(object): 
    def __init__(self): 
     print "first" 

class Second(object): 
    def __init__(self): 
     print "second" 

class Third(First): 
    def __init__(self): 
     print "third" 

class Fourth(Third, Second): 
    def __init__(self): 
     super(Fourth, self).__init__() 
     print "that's it" 
print "Second:" 
print Fourth.__mro__