2013-07-07 15 views
21

Ich versuche, wann und zu verstehen, wie Super() zu verwenden, in Python korrekt (entweder 2.7.x oder 3.x)Python super() Argumente: warum nicht super (obj)?

auf >>> help(super) der Dolmetscher sagt mir, wie es nennen:

class super(object) 
| super(type) -> unbound super object 
| super(type, obj) -> bound super object; requires isinstance(obj, type) 
| super(type, type2) -> bound super object; requires issubclass(type2, type) 

Ich verstehe, dass es in Python3.x jetzt möglich ist, super() innerhalb einer Klassendefinition zu verwenden, aber ich verstehe nicht, warum super(obj) nicht möglich ist. Oder super(self) innerhalb einer Klassendefinition.

Ich weiß, dass es einen Grund dafür geben muss, aber ich kann es nicht finden. Für mich entsprechen diese Zeilen super(obj.__class__, obj) oder super(self.__class__, self) und diese würden richtig funktionieren?

Ich würde denken, dass nur Eingabe super(obj) wäre eine nette Abkürzung sogar in Python 3.x.

+0

Ich würde sagen, dass es Mehrdeutigkeit verursachen würde, wenn Sie "Super" auf einer Metaklasse aufrufen, aber dann erkannte ich, dass diese Zweideutigkeit auch mit der 2-Argument-Form existiert. Jetzt bin ich mir nicht sicher. – user2357112

Antwort

31

Die Zwei-Argument-Form wird nur in Python 2 benötigt. Der Grund ist, dass self.__class__ immer auf die "Blatt" -Klasse im Vererbungsbaum verweist - das heißt, die spezifischste Klasse des Objekts - aber wenn Sie Rufen Sie super auf, müssen Sie ihm mitteilen, welche Implementierung gerade aufgerufen wird, damit er die nächste in der Vererbungsstruktur aufrufen kann.

Angenommen, Sie haben:

class A(object): 
    def foo(self): 
     pass 

class B(A): 
    def foo(self): 
     super(self.__class__, self).foo() 

class C(B): 
    def foo(self): 
     super(self.__class__, self).foo() 

c = C() 

Beachten Sie, dass c.__class__C ist, immer. Denken Sie jetzt darüber nach, was passiert, wenn Sie c.foo() anrufen.

Wenn Sie super(self.__class__, self) in einer Methode von C aufrufen, wird es wie Aufruf super(C, self), was bedeutet "rufen Sie die Version dieser Methode geerbt von C". Das wird B.foo anrufen, was in Ordnung ist. Aber wenn Sie super(self.__class__, self) von B anrufen, ist es immer noch wie super(C, self) aufrufen, denn es ist das gleiche self, also self.__class__ ist immer noch C. Das Ergebnis ist, dass der Anruf in B erneut B.foo aufruft und eine unendliche Rekursion auftritt.

Natürlich, was Sie wirklich wollen, ist aufrufen, und das ist effektiv, was die Python 3 super() tut. In Python 3 können Sie einfach super().foo() tun und es tut das Richtige. Es ist mir nicht klar, was Sie unter super(self) als Abkürzung verstehen. In Python 2 funktioniert es nicht aus dem oben beschriebenen Grund. In Python 3 wäre es ein "Longcut", weil Sie stattdessen einfach super() verwenden können.

Die super(type) und super(type1, type2) Verwendungen können gelegentlich noch in Python 3 benötigt werden, aber diese waren immer eher esoterische Verwendungen für ungewöhnliche Situationen.

+0

Ein Mitarbeiter hat einmal ein Stück einer Methode, die 'Super' genannt hat, in eine separate Methode in einer anderen Klasse umgestaltet, so dass der Code endete" super (SomeOtherClass, some_obj) .method (...) "Das hat perfekt funktioniert, aber es sah für jeden, der den Code las, wie ein Bug aus. Obwohl dies besser ausgedrückt werden könnte (und wurde), kann die Zwei-Argument-Form von "super" in einigen Randfällen immer noch nützlich sein. – user4815162342

+0

Die ersten 4 Zeilen Ihrer Erklärung haben mich alles verstehen lassen. Danke auch für das Beispiel. Das war das fehlende Stück, das ich zu verstehen versuchte. – Gabriel

+0

Wir beziehen uns immer auf einen "esoterischen" oder "Edge" -Fall. Ist das einfach, wenn doppelte Vererbung erfordert, dass wir zwei separate '__init __()' -Funktionen beim Überschreiben von '__init __()' in der Leaf-Klasse aufrufen? –

0

Des Versuch, eine kurze Antwort:

self.__class__ ist immer die tatsächliche („sub-most“) Klasse Ihrer Objektinstanz - nicht unbedingt die gewünschte Klasse, die die Funktion implementiert!

ersetzen super(self.__class__, self) mit super(__class__, self) und Sie sind direkt innerhalb einer Methodendefinition in Python 3, weil Python 3 die magische Zelle Variable __class__ für die implementierende Klasse zur Verfügung stellt.

Und einfach super() mit Null-Argumente ist bereits die Verknüpfung für super(__class__, self) in Python 3. Siehe PEP3135.

Python 2 kennt weder __class__ noch die Nullargumentverknüpfung super().