2011-02-17 61 views
48

我到處看到的例子是超一流的方法應該由被稱爲:Python的超級方法調用替代

super(SuperClass, instance).method(args) 

是否有任何缺點做:

SuperClass.method(instance, args) 

回答

96

考慮以下情況:

class A(object): 
    def __init__(self): 
     print('Running A.__init__') 
     super(A,self).__init__() 
class B(A): 
    def __init__(self): 
     print('Running B.__init__')   
     # super(B,self).__init__() 
     A.__init__(self) 

class C(A): 
    def __init__(self): 
     print('Running C.__init__') 
     super(C,self).__init__() 
class D(B,C): 
    def __init__(self): 
     print('Running D.__init__') 
     super(D,self).__init__() 

foo=D() 

因此類形成所謂的繼承鑽石:

A 
/\ 
    B C 
    \/
    D 

運行代碼產量

Running D.__init__ 
Running B.__init__ 
Running A.__init__ 

這是不好的,因爲C「 s跳過了__init__。原因是因爲B__init__直接調用A__init__

super的用途是解決繼承鑽石。如果您取消註釋

# super(B,self).__init__() 

和註釋掉

A.__init__(self) 

代碼產生了更多desireable結果:

Running D.__init__ 
Running B.__init__ 
Running C.__init__ 
Running A.__init__ 

現在所有的__init__方法被調用。請注意,在您定義B.__init__時,您可能會認爲認爲 0123'與呼叫A.__init__(self)相同,但您會錯誤的。在上述情況下,super(B,self).__init__()實際上調用C.__init__(self)

聖煙,B一無所知C,然而super(B,self)知道調用C__init__?原因是因爲self.__class__.mro()包含C。換句話說,self(或上面的foo)知道約C

所以要小心 - 兩者不可互換。他們可以產生截然不同的結果。

使用superhas pitfalls.在繼承關係圖中的所有類之間需要相當程度的協調。 (他們必須,例如,或者具有相同的調用簽名爲__init__,因爲任何特定__init__不知道其他__init__super下一步可能調用,或其他 use **kwargs)。此外,你必須是有關使用super到處是一致的。跳過一次(如上面的例子),你擊敗了super的整個目的。 查看更多陷阱的鏈接。

如果您完全控制了您的類層次結構,或者避免了繼承菱形,那麼不需要super

+2

+1爲超級有害鏈接。我即將自己發佈。 – 2011-02-17 20:47:59

7

有沒有處罰的,是,儘管你的例子有些誤導。在第一個例子,它應該是

super(SubClass, instance).method(args) # Sub, not SuperClass 

,並導致我引用了Python docs

有兩個典型的用例super的。在具有單一繼承的類層次結構中,可以使用super來引用父類而不顯式命名它們,從而使代碼更易於維護。這種用法與其他編程語言中使用的super非常類似。

第二個用例是在動態執行環境中支持協作多重繼承。這個用例是Python獨有的,在靜態編譯的語言或僅支持單一繼承的語言中找不到。這使得在多個基類實現相同方法的情況下實現「菱形圖」成爲可能。良好的設計規定,這種方法在每種情況下都具有相同的調用簽名(因爲調用順序是在運行時確定的,因爲該順序適用於類層次結構中的更改,並且因爲該順序可以包含運行時未知的同級類)。

基本上,使用第一種方法,你不要使用有硬編碼的父類中有單級的層次,你根本就沒有真正做你想做的(有效/有效)使用多重繼承時的第二種方法。

+1

我是否理解正確,在單一繼承情況下沒有使用`超級`的缺點? – Wolf 2015-02-02 10:08:41