2017-10-20 52 views
3

J'essaie de comprendre comment l'héritage de classe fonctionne dans Python 3, en particulier comment les champs privés interagissent avec les méthodes locales et héritées. Voici quelques exemples pour illustrer le problème.Python3: héritage de classe et champs privés

En premier lieu, si une var variable dans la superclasse est publique, toute méthode dans la sous-classe sera également en mesure de le modifier:

class Superclass: 
    var = 1 
    def getVar(self): 
     print(self.var) 

class Subclass(Superclass): 
    def __init__(self): 
     self.var = 123 

my_object = Subclass() 
my_object.getVar() # outputs 123 

La même chose est pas vrai si la __var variable dans la superclasse est privé, toute méthode héritée ignorera modifications effectuées par le Sous-classe:

class Superclass: 
    __var = 1 
    def getVar(self): 
     print(self.__var) 

class Subclass(Superclass): 
    def __init__(self): 
     self.__var = 123 

my_object = Subclass() 
my_object.getVar() # outputs 1! 

méthodes locales dans la sous-classe peuvent le modifier:

class Superclass: 
    __var = 1 

class Subclass(Superclass): 
    def __init__(self): 
     self.__var = 123 
    def getVar(self): 
     print(self.__var) 

my_object = Subclass() 
my_object.getVar() # outputs 123 

Mais afin d'utiliser une méthode héritée de la valeur modifiée, je dois utiliser self._Superclass__var au lieu de self.__var dans la sous-classe:

class Superclass: 
    __var = 1 
    def getVar(self): 
     print(self.__var) 

class Subclass(Superclass): 
    def __init__(self): 
     self._Superclass__var = 123 

my_object = Subclass() 
my_object.getVar() # outputs 123 

Pourquoi est-ce le cas? Les champs privés ne sont-ils pas hérités par les sous-classes et, par conséquent, la variable self.__var à l'intérieur du Subclass ne pointe PAS à la même valeur que la variable self.__var à l'intérieur de Superclass?

+6

Il n'y a pas de champs privés en Python. Si vous préfixez un nom d'attribut avec '__', vous appelez le nom mangling, où le nom de la classe« owning »est automatiquement inséré afin d'éviter que les noms d'attributs ne soient en conflit dans les sous-classes. Cela ne vous empêche pas d'y accéder, il vous suffit d'inclure le nom de la classe propriétaire. Voir https://docs.python.org/3/tutorial/classes.html#private-variables – kindall

+4

Il n'y a pas de champs privés * en Python. C'est votre malentendu fondamental. Vous utilisez double-underscore name-mangling, qui empêche les collisions de noms dans les classes héritées, pas pour empêcher l'accès.En aparté, j'espère que vous réalisez que vous définissez des * variables de niveau classe *, équivalentes à des "variables statiques" dans d'autres langages, plutôt que des variables d'instance. –

+1

Je pense qu'il vaut la peine d'ajouter cette précision en guise de réponse, car c'est une bonne question pour les personnes venant d'horizons différents. –

Répondre

3

Python n'a pas vraiment variables privées, il existe deux conventions:

  • Variables préfixées avec underscore (_var) sont utilisés pour vous laisser et d'autres personnes savent qu'il est destiné à être privé
  • Variables préfixées avec deux undersores (__var) sont également broyés par l'interpréteur python et sont également préfixé par nom de classe, mais ils sont toujours accessibles comme self._Superclass__var dans votre exemple

Voir aussi le documentation.

Il y a un autre problème dans votre code - vous utilisez des variables de classe, pas des variables d'instance (c'est ce qu'on appelle généralement des variables de classe statiques dans d'autres langues).

Vérifiez cet exemple:

class Superclass: 
    var = 1 

    def getVar(self): 
     print(self.var) 

my_object = Superclass() 
my_object2 = Superclass() 
my_object.getVar() # outputs 1 
my_object2.getVar() # outputs 1 

Superclass.var = 321 # this value is share across all instances 
my_object.getVar() # outputs 321 
my_object2.getVar() # outputs 321 

Et quand vous faites dans vos missions self.var = xxx méthodes, vous cacher que la variable au niveau de la classe et ajouter la nouvelle variable niveau de l'instance avec le même nom.

Voir aussi la documentation: https://docs.python.org/3.6/tutorial/classes.html#class-and-instance-variables

+0

Puisque l'auteur de ces commentaires n'a pas écrit une réponse que je pourrais sélectionner, voudriez-vous ajouter cette information à votre réponse ci-dessus afin que je puisse la sélectionner? Parce que maintenant, aussi utile que soit votre réponse, elle ne répond pas exactement à la question que j'ai soulevée. –

+1

@ gilberto.agostinho.f OK, j'ai mis à jour la réponse. –