2015-03-20 7 views
16

Wir folgen einer Python-Klasse in einem Buch, ich bin beteiligt, die nicht Super für die Initialisierung von einer geerbten Klasse verwendet. Ich habe Probleme, eine klare, verständliche Beschreibung der Unterschiede zwischen diesen beiden Fällen geben:Super init vs. übergeordnete .__ init__

class Parent(object): 

    def __init__(self): 
     .... 


class Child(Parent): 

    def __init__(self): 
     super(Child, self).__init__() 


class Child(Parent): 

    def __init__(self): 
     Parent.__init__(self) 

Aber ich bin peinlich ich zugeben kann nicht erklären, warum ein Fall dem anderen überlegen ist. Kann mir jemand eine klare Erklärung geben?

+3

'Parent .__ init __()' sieht für mich nicht korrekt aus. Ich würde erwarten, dass Sie einen 'TypeError' geben, wenn Sie ihn ausführen. – Kevin

+0

Die letzte gibt Ihnen 'TypeError: ungebundene Methode __init __() muss mit Parent-Instanz als erstes Argument aufgerufen werden (hat nichts stattdessen)', genau weil das Argument fehlt. – dhke

+1

'Elternteil.__init __ (selbst) 'Ich glaube, du meinst, ich mag diese Methode, da sie für mich expliziter ist ... die MRO ist gruselig schwarze Magie –

Antwort

19

Der Zweck von Super ist, Erbschaftdiamanten zu behandeln. Wenn die Vererbungsstruktur der Klasse nur Single-Vererbung verwendet, führt die Verwendung von super() zu denselben Aufrufen wie explizite Aufrufe an die Klasse "parent".

dieses Erbe Diamant Bedenken Sie:

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__() 

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() 

die

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

druckt, während, wenn wir B-B2 ändern und explizite Aufrufe an die Mutter __init__ verwenden:

class B2(A): 
    def __init__(self): 
     print('Running B.__init__')   
     A.__init__(self) 

class D2(B2,C): 
    def __init__(self): 
     print('Running D.__init__') 
     super(D2,self).__init__() 

bar = D2() 

dann die Kette von Initaufrufen wird

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

So wird der Aufruf an C.__init__ vollständig übersprungen.


Es gibt keine bevorzugte Option.

Wenn Sie garantieren können, dass Sie die Mehrfachvererbung nicht unterstützen möchten, sind explizite übergeordnete Anrufe einfacher und übersichtlicher als . Wenn Sie jetzt oder in Zukunft mehrere Vererbungen unterstützen möchten, müssen Sie super() verwenden. Aber verstehen Sie, dass es some pitfalls bei der Verwendung von Super beteiligt sind, aber mit proper use diese Fallstricke vermieden werden können.

+0

Vielleicht vermisse ich etwas, aber das zweite Beispiel scheint nicht die explizite Klasseninitiierung aufzurufen. Es nennt sich einfach super, wie das darüber. –

6

Der Hauptzweck von super(Child, self).__init__(self) ist, dass die Initialisierung im Fall der Mehrfachvererbung mit Diamantvererbungsstrukturen ordnungsgemäß ausgeführt wird. Wenn Sie die Basisklassenkonstruktoren mit Mehrfachvererbung explizit aufrufen, können einige Initialisierer zweimal aufgerufen werden. Bei der einfachen Vererbung gibt es keinen funktionalen Unterschied zwischen der Verwendung von super und dem expliziten Aufruf der Basisklasse __init__(). Beachten Sie, dass die Vererbung immer die Diamantvererbung enthält, da alle Python-Klassen für neue Stile das Objekt subclass verwenden.

Super hat einen geringeren Vorteil des Reduzierens erfordert Änderungen, wenn Sie die Basisklasse umbenennen oder ändern. In Python 3 sind die Argumente super optional. Python 2 erfordert weiterhin, dass Sie die Argumente explizit angeben.

Verwandte Themen