27 votes

Le nom de la méthode Python avec un double fond est surchargé ?

Jetez un coup d'œil à ceci. Notez que la classe B Remplacer A 's a() méthode.

In [1]: class A(object):
   ...:     def __init__(self):
   ...:         self.a()
   ...:     def a(self):
   ...:         print "A.a()"
   ...:         
   ...:         

In [2]: class B(A):
   ...:     def __init__(self):
   ...:         super(B, self).__init__()
   ...:     def a(self):
   ...:         print "B.a()"
   ...:         
   ...:         

In [3]: b = B()
B.a()

Pas de surprise.

Maintenant, regardez ça. Notez que la méthode qui est maintenant surchargée est __a() .

In [7]: class A(object):
   ...:     def __init__(self):
   ...:         self.__a()
   ...:     def __a(self):
   ...:         print "A.__a()"
   ...:         
   ...:         

In [8]: class B(A):
   ...:     def __init__(self):
   ...:         super(B, self).__init__()
   ...:     def __a(self):
   ...:         print "B.__a()"
   ...:         
   ...:         

In [9]: b = B()
A.__a()

Ce comportement m'a surpris.

Quelqu'un peut-il expliquer pourquoi A.__a() est appelé à la place de B.__a() ?

Tout ce qui est __special__ à propos de __a ?

Mise à jour : Après avoir lu la réponse de Sean, j'ai voulu voir si je pouvais surcharger la méthode du nom mangé et j'ai obtenu ce résultat :

In [11]: class B(A):
   ....:     def __init__(self):
   ....:         super(B, self).__init__()
   ....:     def _A__a(self):
   ....:         print "B._A__a()"
   ....:         
   ....:         

In [12]: b = B()
B._A__a()

28voto

Sean Points 637

Les mots-clés dont le motif est __* sont des noms privés de classe.

http://docs.python.org/reference/lexical_analysis.html#reserved-classes-of-identifiers

Je cite :

Les noms de cette catégorie, lorsqu'ils sont utilisés dans le contexte d'une définition de classe, sont réécrits pour utiliser une forme tronquée afin d'éviter les conflits de noms entre les attributs "privés" des classes de base et des classes dérivées.

Manipulation de noms privés (c'est nous qui soulignons) :

Manipulation de noms privés : Lorsqu'un identifiant qui apparaît textuellement dans une définition de classe commence par deux caractères de soulignement ou plus et ne se termine pas par deux caractères de soulignement ou plus, il est considéré comme un nom privé de cette classe. Les noms privés sont transformés en une forme plus longue avant que le code ne soit généré pour eux. La transformation insère le nom de la classe devant le nom, les caractères de soulignement de tête étant supprimés, et un seul caractère de soulignement étant inséré devant le nom de la classe. Par exemple, l'identifiant __spam se produisant dans une classe nommée Ham sera transformée en _Ham__spam . Cette transformation est indépendante du contexte syntaxique dans lequel l'identifiant est utilisé. Si le nom transformé est extrêmement long (plus de 255 caractères), une troncature définie par l'implémentation peut se produire. Si le nom de la classe est constitué uniquement de caractères de soulignement, aucune transformation n'est effectuée.

http://docs.python.org/reference/expressions.html#atom-identifiers

Cela signifie que dans les coulisses, B.__a() est transformé en quelque chose comme B._B__a()

1voto

bnhelp Points 11
In [1]: class A(object):
...:     def __init__(self):
...:         self.a()
...:     def a(self):
...:         print "A.a()"
...:
...:     __str__ = a
...:         

In [2]: class B(A):
...:     def __init__(self):
...:         super(B, self).__init__()
...:     def a(self):
...:         print "B.a()"
...:         
...:         

In [3]: b = B()
        print str(b)
   A.a()

Vous devrez déclarer __str__ à nouveau dans B .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X