super()
Kann in Python 3.x 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
Um diese Arbeit zu machen, wird einige Kompilierung-Magie durchgeführt wird , eine Folge davon ist , dass der folgende Code (die erneut bindet super
an super_
) fehlschlägt:
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 kann super()
die Superklasse zur Laufzeit nicht ohne Unterstützung des Compilers aufgelöst werden? Gibt es praktische Situationen, in denen dieses Verhalten oder der zugrunde liegende Grund einen unachtsamen Programmierer beißen könnte?
... und als Nebenfrage: Gibt es in Python noch andere Beispiele für Funktionen, Methoden usw., die durch erneutes Binden an einen anderen Namen beschädigt werden können?
python
python-3.x
super
Null Piräus
quelle
quelle
Antworten:
Das neue magische
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 bezeichnen, treten dieselben Probleme auf, die Sie bei sichsuper()
selbst festgestellt haben :Gleiches gilt für die Verwendung von Klassendekoratoren, bei denen der Dekorator ein neues Objekt zurückgibt, das den Klassennamen neu bindet:
Die magische
super()
__class__
Zelle umgeht diese Probleme, indem sie Ihnen Zugriff auf das ursprüngliche Klassenobjekt gewährt.Der PEP wurde von Guido ins Leben gerufen, der sich ursprünglich vorstellte
super
, ein Schlüsselwort zu werden , und die Idee, eine Zelle zum Nachschlagen der aktuellen Klasse zu verwenden, war auch seine . Die Idee, daraus ein Schlüsselwort zu machen, war sicherlich Teil des ersten Entwurfs des PEP .Tatsächlich war es jedoch Guido selbst, der sich dann von der Keyword-Idee als "zu magisch" zurückzog und stattdessen die aktuelle Implementierung vorschlug. Er rechnete damit, dass die Verwendung eines anderen Namens
super()
ein Problem sein könnte :Am Ende war es also Guido selbst, der verkündete, dass sich die Verwendung eines
super
Schlüsselworts nicht richtig anfühlte und dass die Bereitstellung einer magischen__class__
Zelle ein akzeptabler Kompromiss war.Ich stimme zu, dass das magische, implizite Verhalten der Implementierung etwas überraschend ist, aber
super()
eine der am häufigsten falsch angewendeten Funktionen in der Sprache ist. Schauen Sie sich einfach alle falsch angewendetensuper(type(self), self)
odersuper(self.__class__, self)
aufgerufenen Aufrufe im Internet an. Wenn einer dieser Codes jemals von einer abgeleiteten Klasse aufgerufen wurde , würde dies zu einer unendlichen Rekursionsausnahme führen . Zumindestsuper()
vermeidet der vereinfachte Aufruf ohne Argumente dieses Problem.Wie für die umbenannten
super_
; Referenz nur__class__
in Ihrer Methode als auch und es wird wieder funktionieren. Die Zelle wird erstellt, wenn Sie in Ihrer Methode entweder auf diesuper
oder auf die__class__
Namen verweisen :quelle
def super(of_class=magic __class__)
Art ähneltself.super(); def super(self): return self.__class__
?super()
ohne Argumente funktioniert. es geht hauptsächlich um das Warum es existiert.super()
ist in einer Klassenmethode äquivalent zusuper(ReferenceToClassMethodIsBeingDefinedIn, self)
, woReferenceToClassMethodIsBeingDefinedIn
zur Kompilierungszeit bestimmt, als geschlossener Abschluss an die Methode angehängt__class__
undsuper()
wird zur Laufzeit vom aufrufenden Frame nachgeschlagen. Aber das alles muss man eigentlich nicht wissen.super()
nicht annähernd eine automatisch instanziierte Funktion , nein.__class__
in Ihrer Methode verwenden . Sie haben den Namensuper
in Ihrer Funktion verwendet. Der Compiler sieht das und fügt den__class__
Abschluss hinzu.type(self)
gibt den aktuellen Typ an, der nicht mit dem Typ identisch ist, für den die Methode definiert ist. So eine KlasseFoo
mit der Methodebaz
Bedürfnissensuper(Foo, self).baz()
, weil es als unterklassiert werden könnteclass Ham(Foo):
, an welchem Punkttype(self)
istHam
undsuper(type(self), self).baz()
würden Ihnen eine Endlosschleife geben. Siehe den Beitrag, auf den ich in meiner Antwort verweise