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?
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
.
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