2016-04-11 13 views
1

Diese Frage ist in Bezug auf die Beiträge bei What does 'super' do in Python?, How do I initialize the base (super) class? und Python: How do I make a subclass from a superclass?, die zwei Möglichkeiten, beschreibt ein SuperClass aus einem SubClass alsExplicit Gang Selbst wenn Superklasse __init__ in Python ruft

class SuperClass: 
    def __init__(self): 
     return 
    def superMethod(self): 
     return 


## One version of Initiation 
class SubClass(SuperClass): 
    def __init__(self): 
     SuperClass.__init__(self) 
    def subMethod(self): 
     return 

oder

zu initialisieren so
class SuperClass: 
    def __init__(self): 
     return 
    def superMethod(self): 
     return 

## Another version of Initiation 
class SubClass(SuperClass): 
    def __init__(self): 
     super(SubClass, self).__init__() 
    def subMethod(self): 
     return 

ich bin ein wenig verwirrt darüber zu müssen explizit Pass self als Parameter in SuperClass.__init__(self) und super(SubClass, self).__init__(). (In der Tat, wenn ich rufe SuperClass.__init__() erhalte ich die Fehler

TypeError: __init__() missing 1 required positional argument: 'self' 

). Aber wenn Konstrukteure oder andere Klassenmethode aufrufen (dh:

## Calling class constructor/initiation 
c = SuperClass() 
k = SubClass() 

## Calling class methods 
c.superMethod() 
k.superMethod() 
k.subMethod() 

), Der self Parameter implizit geben.

Mein Verständnis der self Schlüsselwort ist es nicht anders als die this Zeiger in C++, während es einen Verweis auf die Klasseninstanz bietet. Ist das richtig?

Wenn es immer eine aktuelle Instanz geben würde (in diesem Fall SubClass), warum muss self explizit in den Aufruf von SuperClass.__init__(self) aufgenommen werden? Da

Dank

Antwort

1

in SuperClass.__init__(self), sind Sie die Methode für die Klasse aufrufen, nicht die Instanz, so kann es nicht implizit übergeben werden. Ebenso können Sie nicht einfach SubClass.subMethod() anrufen, aber Sie können und k.subMethod(). Ähnlich, wenn self auf SubClass verweist, dann self.__init__() bedeutet SubClass.__init__(self), also wenn Sie SuperClass.__init anrufen möchten, müssen Sie es direkt anrufen.

1

Die Antwort ist nicht trivial und würde wahrscheinlich einen guten Artikel rechtfertigen. Eine sehr gute Erklärung dafür, wie super() funktioniert, wird brillant von Raymond Hettinger in einem Pycon 2015 Talk, verfügbar here und einem verwandten article gegeben. Ich werde eine kurze Antwort versuchen, und wenn es nicht ausreicht, werde ich (und hoffentlich die Gemeinschaft) darauf erweitern. Die Antwort hat zwei wichtige:

  • Pythons super() Bedürfnisse, auf das ein Objekt haben, wobei das Verfahren außer Kraft gesetzt werden, aufgerufen wird, so wird es explizit mit Selbst weitergegeben. Dies ist nicht die einzige mögliche Implementierung, und in Python 3 ist es nicht mehr erforderlich, dass Sie die Selbstinstanz übergeben.

  • Python super() ist nicht wie Java oder andere kompilierte Sprachen, super. Die Python-Implementierung ist so konzipiert, dass sie das multiple kollaborative Vererbung Paradigma unterstützt, wie in Hettinger's Talk erklärt. Dies hat eine interessante Konsequenz in Python: Die Methodenauflösung in super() hängt nicht nur von der Elternklasse ab, sondern auch von den untergeordneten Klassen (Folge der Mehrfachvererbung). Beachten Sie, dass Hettinger ist mit Python 3.

Die offizielle Python 2.7 documentation on super ist auch eine gute Quelle von Informationen (besser verstanden nach dem Vortrag zu beobachten, meiner Meinung nach).

2

Dies ist einfach Methodenbindung, und hat sehr wenig mit super zu tun. Wenn Sie x.method(*args) können, überprüft Python den Typ x für eine Methode mit dem Namen method. Wenn es eins findet, "bindet" es die Funktion an x, so dass, wenn Sie es aufrufen, x als erster Parameter vor dem Rest der Argumente übergeben wird.

Wenn Sie eine (normale) Methode über ihre Klasse aufrufen, tritt keine solche Bindung auf. Wenn die Methode erwartet, dass ihr erstes Argument eine Instanz ist (z. B. self), müssen Sie sie selbst übergeben.

Die tatsächliche Implementierung dieses Bindungsverhaltens ist ziemlich ordentlich. Python-Objekte sind "Deskriptoren", wenn sie eine Methode (und/oder __set__ oder __delete__ Methoden haben, aber diese sind nicht wichtig für Methoden). Wenn Sie ein Attribut wie a.b nachschlagen, überprüft Python die Klasse a, um zu sehen, ob es ein Attribut b hat, das ein Deskriptor ist. Wenn dies der Fall ist, wird a.b in type(a).b.__get__(a, type(a)) übersetzt. Wenn b eine Funktion ist, wird es eine -Methode haben, die das oben beschriebene Bindungsverhalten implementiert. Andere Arten von Deskriptoren können unterschiedliche Verhaltensweisen haben. Zum Beispiel ersetzt der Dekorator eine Methode durch einen speziellen Deskriptor, der die Funktion der Klasse und nicht die Instanz bindet.

Pythons super erstellt spezielle Objekte, die Attributsuchen anders behandeln als normale Objekte, aber die Details sind für dieses Problem nicht allzu wichtig. Das Bindungsverhalten von Methoden, die über super aufgerufen werden, entspricht genau dem, was ich im ersten Abschnitt beschrieben habe. Daher wird self automatisch an die gebundene Methode übergeben, wenn sie aufgerufen wird. Das Besondere an super ist, dass es eine andere Funktion binden kann, als wenn Sie denselben Methodennamen unter self suchen würden (das ist der Sinn der Verwendung).

0

Das folgende Beispiel könnte die Dinge aufzuklären:

class Example: 
    def method(self): 
     pass 

>>> print(Example.method) 
<unbound method Example.method> 

>>> print(Example().method) 
<bound method Example.method of <__main__.Example instance at 0x01EDCDF0>> 

Wenn ein Verfahren gebunden ist, wird die Instanz implizit übergeben. Wenn eine Methode nicht gebunden ist, muss die Instanz explizit übergeben werden.

Die anderen Antworten werden definitiv mehr Details zum Bindungsprozess bieten, aber ich denke, es lohnt sich, das obige Snippet zu zeigen.