Warum ist super() in Python 3.x magisch?

Lesezeit: 5 Minuten

Warum ist super in Python 3x magisch
Null Piräus

In Python 3.x, super() kann ohne Argumente aufgerufen werden:

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

Damit dies funktioniert, wird zur Kompilierzeit etwas Zauberei ausgeführt, eine Folge davon ist, dass der folgende Code (der erneut bindet super zu super_) schlägt fehl:

super_ = super

class A(object):
    def x(self):
        print("No flipping")

class B(A):
    def x(self):
        super_().x()
>>> B().x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found

Warum ist super() nicht in der Lage, die Superklasse zur Laufzeit ohne Unterstützung durch den Compiler aufzulösen? Gibt es praktische Situationen, in denen dieses Verhalten oder der zugrunde liegende Grund dafür einen unvorsichtigen Programmierer beißen könnte?

… und als Nebenfrage: Gibt es in Python andere Beispiele für Funktionen, Methoden usw., die durch erneutes Binden an einen anderen Namen beschädigt werden können?

  • Ich lasse Armin das erklären eins. Dies ist auch ein weiteres Gut Post

    – Spiele Brainiac

    26. Oktober 13 um 15:01 Uhr


  • verwandt: stackoverflow.com/q/36993577/674039

    – Wim

    17. November 16 um 21:36 Uhr

Warum ist super in Python 3x magisch
Martijn Pieters

Die neue Magie super() Verhalten wurde hinzugefügt, um eine Verletzung des DRY-Prinzips (Don’t Repeat Yourself) zu vermeiden, siehe PEP 3135. Wenn Sie die Klasse explizit benennen müssen, indem Sie sie als global referenzieren, ist dies auch anfällig für dieselben Probleme beim erneuten Binden, die Sie entdeckt haben super() selbst:

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

Dasselbe gilt für die Verwendung von Klassen-Decorators, bei denen der Decorator ein neues Objekt zurückgibt, das den Klassennamen neu bindet:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

Die Magie super() __class__ cell umgeht diese Probleme, indem es Ihnen Zugriff auf das ursprüngliche Klassenobjekt gewährt.

Angestoßen wurde die PEP von Guido, der zunächst angedacht super zum Stichwort werden, und die Idee, eine Zelle zu verwenden, um die aktuelle Klasse nachzuschlagen war auch seins. Sicherlich war die Idee, es zu einem Schlüsselwort zu machen, Teil der erster Entwurf des PEP.

Allerdings war es Guido selbst, der dann trat vom Keyword-Idee als “zu magisch” zurück, und schlägt stattdessen die aktuelle Implementierung vor. Er erwartet, dass mit einem anderen Namen für super() könnte ein Problem sein:

Mein Patch verwendet eine Zwischenlösung: Es geht davon aus, dass Sie es brauchen __class__
wann immer Sie eine Variable namens verwenden 'super'. Also, wenn Sie (global) umbenennen super zu supper und verwenden supper aber nicht super, es wird nicht ohne Argumente funktionieren (aber es wird immer noch funktionieren, wenn Sie es auch übergeben
__class__ oder das eigentliche Klassenobjekt); wenn Sie eine unabhängige Variable mit dem Namen haben super, funktionieren die Dinge, aber die Methode verwendet den etwas langsameren Aufrufpfad, der für Zellvariablen verwendet wird.

Am Ende war es also Guido selbst, der verkündete, dass die Verwendung von a super Schlüsselwort fühlte sich nicht richtig an, und das sorgte für eine Magie __class__ Zelle war ein akzeptabler Kompromiss.

Ich stimme zu, dass das magische, implizite Verhalten der Implementierung etwas überraschend ist, aber super() ist eine der am häufigsten falsch angewendeten Funktionen in der Sprache. Schauen Sie sich einfach alle falsch angewendeten an super(type(self), self) oder super(self.__class__, self) im Internet gefundene Aufrufe; Wenn einer dieser Codes jemals von einer abgeleiteten Klasse aufgerufen wurde, würden Sie am Ende eine unendliche Rekursionsausnahme erhalten. Zumindest vereinfacht super() Aufruf, ohne Argumente, vermeidet das Problem.

Was die Umbenennung betrifft super_; nur Referenz __class__ bei deiner Methode sowie und es wird wieder funktionieren. Die Zelle wird erstellt, wenn Sie entweder auf die verweisen super oder __class__ Namen in Ihrer Methode:

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping

  • Gutes Aufschreiben. Es ist aber immer noch so klar wie Schlamm. Sie sagen, dass super() einer automatisch instanziierten Funktion wie äquivalent ist def super(of_class=magic __class__) so ähnlich wie ein self.super(); def super(self): return self.__class__?

    – Karl Merriam

    14. März 14 um 16:28 Uhr

  • @CharlesMerriam: In diesem Beitrag geht es nicht darum, wie super() ohne Argumente funktioniert; es handelt sich hauptsächlich um die warum Es existiert. super(), in einer Klassenmethode, ist äquivalent zu super(ReferenceToClassMethodIsBeingDefinedIn, self), wo ReferenceToClassMethodIsBeingDefinedIn wird zur Kompilierzeit bestimmt und an die Methode als Abschlussnamen angehängt __class__, und super() wird zur Laufzeit beide aus dem aufrufenden Frame nachschlagen. Aber eigentlich muss man das alles gar nicht wissen.

    – Martijn Pieters

    14. März 14 um 16:37 Uhr


  • @CharlesMerriam: aber super() ist bei weitem nicht ein automatisch instanziierte Funktion, Nein.

    – Martijn Pieters

    14. März 14 um 16:38 Uhr

  • @chris.leonard: der Schlüsselsatz ist Die Zelle wird erstellt, wenn Sie super() oder use verwenden __class__ bei deiner Methode. Sie haben den Namen verwendet super in Ihrer Funktion. Der Compiler sieht das und fügt die hinzu __class__ Schließung.

    – Martijn Pieters

    10. Februar 18 um 18:27 Uhr


  • @Alexey: Es ist nicht genügend. type(self) gibt die Strom Typ, der nicht mit dem Typ identisch ist, für den die Methode definiert ist. Also eine Klasse Foo mit Methode baz braucht super(Foo, self).baz(), weil es als Unterklasse eingestuft werden könnte class Ham(Foo):, an welchem ​​Punkt type(self) ist Ham und super(type(self), self).baz() würde Ihnen eine Endlosschleife geben. Siehe den Beitrag, auf den ich in meiner Antwort verlinke: Kann ich beim Aufrufen von super() in einer abgeleiteten Klasse self.__class__ übergeben?

    – Martijn Pieters

    23. Februar 18 um 17:37 Uhr


.

805770cookie-checkWarum ist super() in Python 3.x magisch?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy