not - python super multiple inheritance
¿Por qué es la magia súper(Python) 3.x? (1)
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 que esto funcione, se realiza algo de magia en tiempo de compilación, una consecuencia de lo cual es que el siguiente código (que se 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 "<stdin>", line 1, in <module>
File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found
¿Por qué super()
no puede resolver la superclase en tiempo de ejecución sin ayuda del compilador? ¿Hay situaciones prácticas en las que este comportamiento, o la razón subyacente para ello, podría morder a un programador incauto?
... y, como una pregunta complementaria: ¿hay algún otro ejemplo en Python de funciones, métodos, etc. que se pueda romper volviéndolos a unir a un nombre diferente?
Se agregó el nuevo comportamiento mágico super()
para evitar violar el principio DRY (No repetir), ver PEP 3135 . Tener que nombrar explícitamente la clase al hacer referencia a ella como global también es proclive a los mismos problemas de reenlace que descubrió con super()
sí mismo:
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 enlazar 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 mágica super()
__class__
elude estos problemas al darle acceso al objeto de la clase original.
El PEP fue iniciado por Guido, quien inicialmente se imaginó que se convertiría en una palabra clave , y la idea de usar una celda para buscar la clase actual también era suya . Ciertamente, la idea de convertirla en una palabra clave fue parte del primer borrador del PEP .
Sin embargo, fue el propio Guido quien se alejó de la idea de la palabra clave como "demasiado mágico" , proponiendo la implementación actual en su lugar. Anticipó que usar un nombre diferente para super()
podría ser un problema :
Mi parche usa una solución intermedia: supone que necesita
__class__
cada vez que usa una variable llamada''super''
. Por lo tanto, si (globalmente) renombrasuper
a lasupper
y utiliza lasupper
pero no essuper
, no funcionará sin argumentos (pero seguirá funcionando si lo pasa__class__
o el objeto de la clase real); si tiene una variable no relacionada denominadasuper
, las cosas funcionarán, pero el método utilizará la ruta de llamada ligeramente más lenta utilizada para las variables de celda.
Entonces, al final, fue el propio Guido quien proclamó que usar una palabra clave super
no se sentía bien, y que proporcionar una celda mágica __class__
era un compromiso aceptable.
Estoy de acuerdo en que el comportamiento mágico e 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 super(type(self), self)
o super(self.__class__, self)
encuentran en Internet; si se llamaba alguna vez de ese código desde una clase derivada , terminarías con una excepción de recursión infinita . Por lo menos, la llamada a super()
simplificada, sin argumentos, evita ese problema.
En cuanto al super_
rebautizado; simplemente __class__
referencia a __class__
en su método también y funcionará nuevamente. 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