关于python的继承的一个疑问
迷茫
迷茫 2017-04-18 10:28:50
0
3
898

如图所示,B 类继承了 A 类;

当实例化对象时,B 类中没有构造函数, 应该调用父类的构造函数 __init__

但是里边的 self.__pirv() 为啥调用到父类 A__priv, 而 self.pub() 又调到 B 中的 pub

求解?

迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

répondre à tous(3)
左手右手慢动作

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 :

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.

巴扎黑

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

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal