En Python, le nom de la méthode commençant par __ n'est pas privé. __ signifie laisser Python effectuer la modification du nom. Le résultat de la modification du nom est _A__priv. Vous ne devez pas écraser en utilisant cette méthode. Si vous souhaitez qu'une sous-classe écrase une méthode, vous ne pouvez utiliser que _, pas __
Lorsque l'instance de la sous-classe appelle la méthode __init__(), la méthode B est trouvée à partir de la sous-classe pub() elle-même. Évidemment, elle existe, donc la méthode B de la classe pub() elle-même sera. appelé; cependant, dans Lors de l'appel de la méthode __priv(), en raison de l'adaptation du nom par Python des membres privés, ce que vous appelez en réalité est la méthode _A__priv(), et une telle méthode n'existe pas dans le B classe, et certains n'en ont que _B__priv() , donc A dans la classe parent _A__priv() est appelé, ce qui donne ce résultat. Ceci est ma compréhension personnelle, veuillez me corriger si je me trompe, merci.
Quant au problème en lui-même, @Xavier et @Christoph l'ont déjà expliqué en détail
Si vous ne comprenez toujours pas, vous pouvez essayer ceci :
Code d'origine :
class A:
def __init__(self):
self.__priv() # 等等改成 self._A__priv()
self.public()
def __priv(self): # 等等改成 def _A__priv(self):
print('private of A')
def public(self):
print('public of A')
class B(A):
def __priv(self): # 等等改成 self._B__priv(self):
print('private of B')
def public(self):
print('public of B')
b = B()
Faites-le manuellement en modifiant le nom :
class A:
def __init__(self):
self._A__priv()
self.public()
def _A__priv(self):
print('private of A')
def public(self):
print('public of A')
class B(A):
def _B__priv(self):
print('private of B')
def public(self):
print('public of B')
b = B()
B hérite ici de tous les attributs de A, notamment :
__init__
_A__priv
public
et B se définissent :
_B__priv
public (le A de public est écrasé ici)
Alors enfin vous verrez dir(b) qui contient :
__init__ (hérité de A)
_A__priv (hérité de A)
_B__priv (votre propre définition)
public (votre propre définition)
Enfin, lorsque __init__ est appelé, _A__priv sera appelé, et B a cette méthode à l'intérieur de
Je voudrais ajouter que Python lui-même n'a pas de véritable mécanisme privé, car les personnes qui comprennent la modification des noms peuvent accéder aux attributs commençant par un double trait de soulignement. Par exemple, je peux facilement écrire :
.
a = A()
a._A__priv() # 防都防不住
Pour faire simple, ce mécanisme est :
Un mécanisme anti-imbécile n'est pas un mécanisme anti-méchant,
Un mécanisme pour empêcher les accès accidentels, et non un mécanisme pour empêcher les accès délibéré
Mais tout le monde ne pense pas que ce mécanisme est bon (personnellement, je ne l'aime pas. Utiliser un double trait de soulignement pour commencer le nom est gênant et pas très utile), vous pouvez donc le trouver dans beaucoup de code python : les gens souvent utilisez Une méthode de protection unique au début, cette approche est une pratique reconnue (Note 1), elle suffit à éviter les imbéciles pour les programmeurs légèrement expérimentés, et il n'y aura pas d'effets supplémentaires ou de situations inattendues.
Ian Bicking a un passage qui dit ceci (Ian Bicking est un maître Python, j'ai vu ce passage dans Fluent Python de Luciano Ramalho) :
N'utilisez jamais deux lignes de base devant. C'est extrêmement égoïste, et si vous ne voulez pas créer de conflit de nom (Remarque 2), vous pouvez remodeler le nom explicitement (par exemple : _MyThing_blahblah). Essentiels C'est la même chose que d'utiliser un double résultat, mais c'est public, alors qu'un double résultat est un comportement privé.
Ma suggestion est donc d'utiliser _priv serait un meilleur choix.
Remarque 1 : Les attributs commençant par un seul trait de soulignement n'ont pas de propriétés particulières. Ce sont simplement des techniques symboliques qui s'appuient sur le consensus des programmeurs Python, tout comme certains langages utilisent const pour marquer des constantes, et on peut aussi simplement s'appuyer sur le consensus des constantes utilisant des noms en majuscules pour éviter des situations inattendues
Remarque 2 : La raison pour laquelle vous souhaitez protéger les attributs avec des propriétés privées est que la raison la plus courante est un accès accidentel causé par des conflits de noms
En Python, le nom de la méthode commençant par __ n'est pas privé. __ signifie laisser Python effectuer la modification du nom. Le résultat de la modification du nom est _A__priv. Vous ne devez pas écraser en utilisant cette méthode. Si vous souhaitez qu'une sous-classe écrase une méthode, vous ne pouvez utiliser que _, pas __
Après avoir réfléchi un moment à cette question, voici ma compréhension :
Lorsque l'instance de la sous-classe appelle la méthode
__init__()
, la méthodeB
est trouvée à partir de la sous-classepub()
elle-même. Évidemment, elle existe, donc la méthodeB
de la classepub()
elle-même sera. appelé; cependant, dans Lors de l'appel de la méthode__priv()
, en raison de l'adaptation du nom par Python des membres privés, ce que vous appelez en réalité est la méthode_A__priv()
, et une telle méthode n'existe pas dans leB
classe, et certains n'en ont que_B__priv()
, doncA
dans la classe parent_A__priv()
est appelé, ce qui donne ce résultat. Ceci est ma compréhension personnelle, veuillez me corriger si je me trompe, merci.Quant au problème en lui-même, @Xavier et @Christoph l'ont déjà expliqué en détail
Si vous ne comprenez toujours pas, vous pouvez essayer ceci :
Code d'origine :
Faites-le manuellement en modifiant le nom :
B
hérite ici de tous les attributs deA
, notamment :__init__
_A__priv
public
et
B
se définissent :_B__priv
public
(leA
depublic
est écrasé ici)Alors enfin vous verrez
dir(b)
qui contient :__init__
(hérité deA
)_A__priv
(hérité deA
)_B__priv
(votre propre définition)public
(votre propre définition)Enfin, lorsque
__init__
est appelé,_A__priv
sera appelé, etB
a cette méthode à l'intérieur deJe voudrais ajouter que Python lui-même n'a pas de véritable mécanisme privé, car les personnes qui comprennent la modification des noms peuvent accéder aux attributs commençant par un double trait de soulignement. Par exemple, je peux facilement écrire :
.Pour faire simple, ce mécanisme est :
Un mécanisme anti-imbécile n'est pas un mécanisme anti-méchant,
Un mécanisme pour empêcher les accès accidentels, et non un mécanisme pour empêcher les accès délibéré
Mais tout le monde ne pense pas que ce mécanisme est bon (personnellement, je ne l'aime pas. Utiliser un double trait de soulignement pour commencer le nom est gênant et pas très utile), vous pouvez donc le trouver dans beaucoup de code python : les gens souvent utilisez Une méthode de protection unique au début, cette approche est une pratique reconnue (Note 1), elle suffit à éviter les imbéciles pour les programmeurs légèrement expérimentés, et il n'y aura pas d'effets supplémentaires ou de situations inattendues.
Ian Bicking a un passage qui dit ceci (Ian Bicking est un maître Python, j'ai vu ce passage dans Fluent Python de Luciano Ramalho) :
Ma suggestion est donc d'utiliser
_priv
serait un meilleur choix.Remarque 1 : Les attributs commençant par un seul trait de soulignement n'ont pas de propriétés particulières. Ce sont simplement des techniques symboliques qui s'appuient sur le consensus des programmeurs Python, tout comme certains langages utilisent
const
pour marquer des constantes, et on peut aussi simplement s'appuyer sur le consensus des constantes utilisant des noms en majuscules pour éviter des situations inattenduesRemarque 2 : La raison pour laquelle vous souhaitez protéger les attributs avec des propriétés privées est que la raison la plus courante est un accès accidentel causé par des conflits de noms
Questions auxquelles j'ai répondu : Python-QA