2014-02-25 34 views
0

我有一個繼承的類並覆蓋了一個方法,它也從基類繼承。但事情是,中間方法創建一個異常,我想通過調用第一個聲明的方法繞過。有沒有辦法指定mro忽略第二個電話?Python超級繞過MRO

一個例子可以是:

class Base(object): 
    def __init__(self): 
     res = "Want this" 
     print res 

class BaseA(Base): 
     def __init__(self): 
      res = super(BaseA, self).__init__() 
      res = "Not this" 
      print res 

class BaseB(BaseA): 
     def __init__(self): 
      res = super(BaseB, self).__init() 
      #At this poing res is "Not this" 
      #The desire is that it would be "Want this" 
      print res 

非常感謝

PD: 喜歡的東西類BaseB(基地BaseA)可以工作?

+0

「類BaseB(Base,BaseA)可以工作嗎?」。不,它會引發異常:調用元類時出現TypeError:錯誤 無法爲基Base,BaseA'創建一致的方法解析 order(MRO)。在這種情況下,你必須直接調用特定的父類... – Bakuriu

回答

3

通常情況下您會修改該方法。

但是,super()的第一個參數是從開始搜索下一個方法的地方。通常情況下這會是當前的類,但你也可以通過在基類:

class BaseB(BaseA): 
    def __init__(self): 
     res = super(BaseA, self).__init__() 

這裏,super()需要的type(self)的MRO,在MRO發現BaseA,並尋找下一個類實現__init__

另一種方法繞過問題__init__方法是隻需調用未結合的方法上Base直接:

class BaseB(BaseA): 
    def __init__(self): 
     res = Base.__init__(self) 

繞過任何MRO完全搜索。

+0

非常感謝。它繞過超級並直接調用基類__init__。一個簡單有效的解決方案,太棒了。爲了好奇心,我分支並測試第一個修復程序,看看發生了什麼。 – cllamach

0

如何回合剛剛

Base.__init__(self)

1

使用正確的方法解決這個問題是創建一個新的類層次結構,其覆蓋與改進執行違規方法。如果你堅持兩輪牛車雖然,這可能是你想要什麼:

class BaseB(BaseA): 
     def __init__(self): 
      res = super(BaseA, self).__init() 
      #At this poing res is "Not this" 
      #The desire is that it would be "Want this" 
      print res 

請注意,我所要求的超級實現相對於BaseA,這意味着BaseA實現從未使用過。


然而,這可以做的時候菱形繼承涉及錯誤的事情。試想一下:

class Base(object): 
    def __init__(self): 
     print 'initing Base' 

class BaseA(Base): 
    def __init__(self): 
     print 'initing BaseA' 
     res = super(BaseA, self).__init__() 

class BaseB(BaseA): 
    def __init__(self): 
     print 'initing BaseB' 
     res = super(BaseA, self).__init__() 

class BaseC(BaseA): 
    def __init__(self): 
     print 'initing BaseC' 
     res = super(BaseC, self).__init__() 

class BaseD(BaseB, BaseC): 
    def __init__(self): 
     print 'initing BaseD' 
     res = super(BaseD, self).__init__() 

print BaseD() 

輸出是:

initing BaseD 
initing BaseB 
initing Base 
<__main__.BaseD object at 0x7f1e693a0110> 

BaseC被跳過,即使這不是我們想要的。這是因爲BaseC在方法解析順序中出現在BaseBBaseA之間,所以當我們從BaseB跳到BaseA時,我們無意中忽略了BaseC

>>> print [cls.__name__ for cls in BaseD.mro()] 
['BaseD', 'BaseB', 'BaseC', 'BaseA', 'Base', 'object'] 
+0

'super(BaseA,self)'仍然使用'type(self)'的MRO,不需要在這裏自己進行計算。 –

+0

如果'self'的類型是'class BaseD(BaseA,BaseB)',那麼上面的代碼會產生一個無限循環,否?我只是想說明,在鑽石繼承的情況下這不是那麼容易。 – bukzor

+0

蟒蛇防禦;你不能創建'class BaseD':'TypeError:錯誤時調用元類基地\ n不能創建一個一致的方法解析\諾德(MRO)BaseB BaseA' –