Nom de classe codé en dur passé à super

Le
Alex Marandon
Bonjour,

Tous les exemples d'utilisation de super que j'ai rencontrés passent la
classe appellante en la nommant explicitiment: super(C, self).methode()
Est-ce juste une convention ou bien y a-t-il une raison technique ?
Pourquoi ne pas utiliser super(self.__class__, self).method() à la place
? De cette manière, si on renommait la classe on aurait pas à modifier
aussi l'appel à super.

Merci,
Alex
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Amaury Forgeot d'Arc
Le #18018861
Alex Marandon a écrit :
Bonjour,

Tous les exemples d'utilisation de super que j'ai rencontrés passent la
classe appellante en la nommant explicitiment: super(C, self).methode()
Est-ce juste une convention ou bien y a-t-il une raison technique ?
Pourquoi ne pas utiliser super(self.__class__, self).method() à la place
? De cette manière, si on renommait la classe on aurait pas à modifier
aussi l'appel à super.



Ah, mais c'est que ça ne marche pas (sinon super() l'aurait déjà fait).
si on prend l'exemple suivant:

class A(object):
def f(self):
print "A.f()"

class B(A):
def f(self):
print "B.f()"
super(B, self).f()

class C(B):
pass

x = C()
x.f()

Cela imprime "B.f()" puis "A.f()", et tout est normal.

Essaie maintenant de remplacer
super(B, self).f()
par
super(self.__class__, self).f()
et boum, un bel appel en boucle qui se brise sur le mur de la récursion.

La raison, c'est que même à l'intérieur de la fonction B.f,
self.__class__ == C, et donc super() commence par chercher dans B (la
classe qui suit C dans la liste des bases)
Ce qui compte pour super(), ce n'est pas la classe de l'objet, mais la
classe qui contient le code de la méthode. Il faut donc bien indiquer
l'objet classe.


Cela peut poser des problèmes, en particulier si la classe B est
redéfinie. C'est pour cela que python 3.0 (qui sort mercredi!) a trouvé
la parade:

class B(A):
def f(self):
super().f()

C'est presque magique: chaque méthode définit une variable cachée
('__class__') qui représente la classe qui contient la fonction. On y
ajoute le premier paramètre de la fonction, et voilà enfin un vrai super().


--
Amaury Forgeot d'Arc
Bruno Desthuilliers
Le #18021351
Alex Marandon a écrit :
Bonjour,

Tous les exemples d'utilisation de super que j'ai rencontrés passent la
classe appellante en la nommant explicitiment: super(C, self).methode()
Est-ce juste une convention ou bien y a-t-il une raison technique ?



Il y a une raison technique. super() doit savoir à partir d'où (dans le
mro) il est appelé pour effectuer une résolution correcte (en d'autres
termes : pour savoir à quel position on se situe dans le mro au moment
de l'appel). Il lui faut donc la classe _dans laquelle la méthode est
définie_, et non la classe de l'instance sur laquelle la méthode est
appelée.

Pourquoi ne pas utiliser super(self.__class__, self).method() à la place
?



Parce que dans ce cas, la résolution ne sera correcte que si
self.__class__ est la classe dans laquelle method est définie.

class Parent(object):
def method(self):
print "in Parent.method - self.__class__ is ", self.__class__
print "super(Parent, self):", super(Parent, self)
print "super(self.__class__, self):", super(self.__class__, self)
print

class Child(Parent):
def method(self):
print "in Child.method - self.__class__ is ", self.__class__
print "calling super(Child, self).method:"
super(Child, self).method()

print "calling super(self.__class__, self).method"
if type(self) is GrandChild:
print "self.__class__ is GrandChild, so here, "
"super(self.__class__, self).method resolves to
Child.method"
print "enjoy the nice infinite recursion...."
print
super(self.__class__, self).method()
print

class GrandChild(Child):
def method(self):
print "in GrandChild.method - self.__class__ is ", self.__class__
print "calling super(GrandChild, self).method:"
super(GrandChild, self).method()


for obj in (Parent(), Child(), GrandChild()):
obj.method()
print "---n"


De cette manière, si on renommait la classe on aurait pas à modifier
aussi l'appel à super.



Ton éditeur n'est pas capable de faire un simple rechercher/remplacer ?-)
Alex Marandon
Le #18023621
Bruno Desthuilliers wrote:
Alex Marandon a écrit :
Bonjour,

Tous les exemples d'utilisation de super que j'ai rencontrés passent
la classe appellante en la nommant explicitiment: super(C,
self).methode() Est-ce juste une convention ou bien y a-t-il une
raison technique ?



Il y a une raison technique. super() doit savoir à partir d'où (dans le
mro) il est appelé pour effectuer une résolution correcte (en d'autres
termes : pour savoir à quel position on se situe dans le mro au moment
de l'appel). Il lui faut donc la classe _dans laquelle la méthode est
définie_, et non la classe de l'instance sur laquelle la méthode est
appelée.



Je comprends, merci à toi et Amaury et vivement Python 3 :)
Amaury Forgeot d'Arc
Le #18027541
Alex Marandon a écrit :
Bruno Desthuilliers wrote:
Alex Marandon a écrit :
Bonjour,

Tous les exemples d'utilisation de super que j'ai rencontrés passent
la classe appellante en la nommant explicitiment: super(C,
self).methode() Est-ce juste une convention ou bien y a-t-il une
raison technique ?



Il y a une raison technique. super() doit savoir à partir d'où (dans
le mro) il est appelé pour effectuer une résolution correcte (en
d'autres termes : pour savoir à quel position on se situe dans le mro
au moment de l'appel). Il lui faut donc la classe _dans laquelle la
méthode est définie_, et non la classe de l'instance sur laquelle la
méthode est appelée.



Je comprends, merci à toi et Amaury et vivement Python 3 :)



Après-demain Inch'Allah.

--
Amaury
Publicité
Poster une réponse
Anonyme