En Python 3.x, se puede llamar a super()
sin argumentos:
class A(object): def x(self): print("Hey now") class B(A): def x(self): super().x()
>>> B().x() Hey now
Para hacer este trabajo, se realiza algo de magia en tiempo de comstackción, una consecuencia de la cual es que el siguiente código (que vuelve a super_
super
a super_
) falla:
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 "", line 1, in File "", line 3, in x RuntimeError: super(): __class__ cell not found
¿Por qué super()
no puede resolver la superclase en tiempo de ejecución sin la asistencia del comstackdor? ¿Hay situaciones prácticas en las que este comportamiento, o la razón subyacente para ello, podría morder a un progtwigdor incauto?
… y, como una pregunta complementaria: ¿hay otros ejemplos en Python de funciones, métodos, etc. que puedan romperse volviéndolos a unir un nombre diferente?
El nuevo comportamiento de la magia super()
se agregó para evitar violar el principio DRY (No se repita), vea PEP 3135 . Tener que nombrar explícitamente a la clase al hacer referencia a ella como global también es propenso a los mismos problemas de reencuadernación que descubrió con super()
:
class Foo(Bar): def baz(self): return super(Foo, self).baz() + 42 Spam = Foo Foo = something_else() Spam().baz() # liable to blow up
Lo mismo se aplica al uso de decoradores de clase donde el decorador devuelve un nuevo objeto, que vuelve a unir el nombre de la clase:
@class_decorator_returning_new_class class Foo(Bar): def baz(self): # Now `Foo` is a *different class* return super(Foo, self).baz() + 42
La celda magic super()
__class__
evita estos problemas muy bien al brindarle acceso al objeto de clase original.
El PEP fue iniciado por Guido, quien inicialmente imaginó que el super
convertiría en una palabra clave , y la idea de usar una celda para buscar la clase actual también fue suya . Ciertamente, la idea de convertirla en una palabra clave fue parte del primer borrador del PEP .
Sin embargo, fue en realidad el mismo Guido quien luego se alejó de la idea de la palabra clave como “demasiado mágica” , proponiendo la implementación actual en su lugar. Él anticipó que usar un nombre diferente para super()
podría ser un problema :
Mi parche usa una solución intermedia: asume que necesitas
__class__
siempre que uses una variable llamada'super'
. Por lo tanto, si (globalmente) cambiasuper
nombre desuper
asupper
y usasupper
pero nosuper
, no funcionará sin argumentos (pero seguirá funcionando si lo pasa__class__
o el objeto de clase real); Si tiene una variable no relacionada llamadasuper
, las cosas funcionarán, pero el método usará la ruta de llamada ligeramente más lenta utilizada para las variables de celda.
Entonces, al final, fue el mismo Guido el que proclamó que usar una super
palabra clave no se sentía bien, y que proporcionar una celda mágica de __class__
era un compromiso aceptable.
Estoy de acuerdo en que la magia, el comportamiento implícito de la implementación es algo sorprendente, pero super()
es una de las funciones más mal aplicadas en el lenguaje. Solo eche un vistazo a todas las invocaciones de super(type(self), self)
o super(self.__class__, self)
encontradas en Internet; si alguna vez se llamara a ese código desde una clase derivada , terminaría con una excepción de recursión infinita . Por lo menos la llamada super()
simplificada, sin argumentos, evita ese problema.
En cuanto a los super_
renombrados; simplemente __class__
referencia a __class__
en su método también y funcionará de nuevo. La celda se crea si hace referencia a los nombres super
o __class__
en su método:
>>> 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