En Python 3.x, super()
peut être appelé sans arguments:
class A(object):
def x(self):
print("Hey now")
class B(A):
def x(self):
super().x()
>>> B().x()
Hey now
Afin de faire ce travail, une certaine magie lors de la compilation est effectuée, dont une conséquence est que le code suivant (qui se lie super
à super_
) échoue:
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
Pourquoi est-il super()
impossible de résoudre la superclasse au moment de l'exécution sans l'aide du compilateur? Existe-t-il des situations pratiques dans lesquelles ce comportement, ou la raison sous-jacente de celui-ci, pourrait mordre un programmeur imprudent?
... et, en guise de question secondaire: y a-t-il d'autres exemples en Python de fonctions, méthodes, etc. qui peuvent être brisés en les reliant à un nom différent?
python
python-3.x
super
Zéro Pirée
la source
la source
Réponses:
Le nouveau
super()
comportement magique a été ajouté pour éviter de violer le principe DRY (Don't Repeat Yourself), voir PEP 3135 . Devoir nommer explicitement la classe en la référençant comme un global est également sujet aux mêmes problèmes de reliure que vous avez découverts avecsuper()
lui-même:La même chose s'applique à l'utilisation de décorateurs de classe où le décorateur renvoie un nouvel objet, qui relie le nom de la classe:
La
super()
__class__
cellule magique évite ces problèmes en vous donnant accès à l'objet de classe d'origine.Le PEP a été lancé par Guido, qui envisageait initialement de
super
devenir un mot-clé , et l'idée d'utiliser une cellule pour rechercher la classe actuelle était également la sienne . Certes, l'idée d'en faire un mot-clé faisait partie de la première ébauche du PEP .Cependant, c'est en fait Guido lui-même qui s'est ensuite éloigné de l'idée de mot-clé comme «trop magique» , proposant plutôt l'implémentation actuelle. Il prévoyait que l'utilisation d'un nom différent pour
super()
pourrait être un problème :Donc, à la fin, c'est Guido lui-même qui a proclamé que l'utilisation d'un
super
mot-clé ne se sentait pas bien, et que fournir une__class__
cellule magique était un compromis acceptable.Je conviens que le comportement magique et implicite de l'implémentation est quelque peu surprenant, mais
super()
c'est l'une des fonctions les plus mal appliquées du langage. Jetez un œil à toutes les invocations mal appliquéessuper(type(self), self)
ousuper(self.__class__, self)
trouvées sur Internet; si l'un de ces codes était appelé à partir d'une classe dérivée, vous vous retrouveriez avec une exception de récursivité infinie . À tout le moins, l'super()
appel simplifié , sans arguments, évite ce problème.Quant à la renommée
super_
; simplement référence__class__
dans votre méthode aussi bien et ça va fonctionner à nouveau. La cellule est créée si vous référencez les nomssuper
ou__class__
dans votre méthode:la source
def super(of_class=magic __class__)
peu comme unself.super(); def super(self): return self.__class__
?super()
sans arguments; il traite principalement du pourquoi il existe.super()
, dans une méthode de classe, équivaut àsuper(ReferenceToClassMethodIsBeingDefinedIn, self)
, oùReferenceToClassMethodIsBeingDefinedIn
est déterminé au moment de la compilation, attaché à la méthode en tant que fermeture nommée__class__
, etsuper()
recherchera les deux dans le cadre appelant au moment de l'exécution. Mais vous n'avez pas vraiment besoin de savoir tout cela.super()
est loin d'être une fonction automatiquement instanciée , non.__class__
dans votre méthode . Vous avez utilisé le nomsuper
dans votre fonction. Le compilateur voit cela et ajoute la__class__
fermeture.type(self)
donne le type actuel , qui n'est pas le même que le type sur lequel la méthode est définie. Donc, une classeFoo
avec desbaz
besoins de méthodesuper(Foo, self).baz()
, car elle pourrait être sous-classée commeclass Ham(Foo):
, à quel pointtype(self)
estHam
etsuper(type(self), self).baz()
vous donnerait une boucle infinie. Voir le message auquel je renvoie