Maison > Questions et réponses > le corps du texte
如图所示,B
类继承了 A
类;
当实例化对象时,B
类中没有构造函数, 应该调用父类的构造函数 __init__
但是里边的 self.__pirv()
为啥调用到父类 A
的 __priv
, 而 self.pub()
又调到 B
中的 pub
求解?
ringa_lee2017-04-18 10:30:50
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 __
大家讲道理2017-04-18 10:30:50
Après avoir réfléchi un moment à cette question, voici ma compréhension :
class A(object):
def __init__(self):
self.__priv() # _A__priv()
self.pub()
def __priv(self):
print("private A")
def pub(self):
print("public A")
class B(A):
def __init__(self):
self.__priv() # 调用_B__priv()对比
super(B, self).__init__() # 在这里显式调用父类的`__init__()`方法
def __priv(self):
print("private B")
def pub(self):
print("public B")
if __name__ == '__main__':
b = B()
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.
巴扎黑2017-04-18 10:30:50
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
Questions auxquelles j'ai répondu : Python-QA