2013-09-27 2 views
8

J'ai le code suivant.Pourquoi la classe enfant n'hérite-t-elle pas la méthode de la classe parente dans python dans cet exemple?

class Foo(object): 
    def __init__(self): 
     self.__baz = 40 
    def foo(self): 
     print self.__baz 

class Bar(Foo): 
    def __init__(self): 
     #super(Bar, self).__init__() 
     self.__baz = 21 
    def bar(self): 
     print self.__baz 

x = Bar() 
x.foo() 
x.bar() 

Je reçois cette erreur:

Traceback (most recent call last): 
    File "classes.py", line 15, in <module> 
    x.foo() 
    File "classes.py", line 5, in foo 
    print self.__baz 
AttributeError: 'Bar' object has no attribute '_Foo__baz' 

pourquoi est la méthode foo pas hérité dans Bar.

EDIT: Cela fonctionne très bien, si vous appelez super qui est mis en commentaire.

+3

Vous ne savez pas, mais n'est-ce pas parce que __variablename est une variable spéciale? http://stackoverflow.com/a/1301369/2537322 – meyer9

+0

Plus curieusement, pourquoi cela * fonctionne * si vous appelez 'super()'? –

+0

Pas une réponse, mais ajoute plus de détails - si vous le changez de '__baz' à' baz' les deux appels impriment 21. Si vous appelez 'super()' et laissez comme '__baz' ils impriment '40' et' 21' respectivement. –

Répondre

7

Les attributs double underscore ont leurs noms mutilées basé sur l'espace de noms actuel /contenant. Dans la fonction foo, l'espace de noms actuel est Foo. Par conséquent, lorsque Python recherche self.__baz, il recherchera en fait en raison du schéma de gestion des noms. Puisque nulle part dans Foo avez-vous réellement défini un attribut __baz, la classe n'a pas d'attribut _Foo__baz (il a un attribut _Bar__baz puisque vous avez défini self.__baz dans une méthode au sein de Bar).

Bien sûr, comme vous l'avez probablement remarqué, si vous appelez Foo.__init__(self) dans Baz.__init__ (directement ou via super), vous verrez disparaître le problème parce que Foo.__init__ ensembles __baz (à savoir _Foo__baz).

+0

donc la méthode foo n'est pas héritée correcte? Je suis un peu confus quant à ce qui se passe ici ... –

+0

@ user1988876 - la méthode 'foo' * est * héritée. Mais quand vous l'appelez, l'attribut auquel il essaie d'accéder est * manquant *. Quand python voit 'self .__ baz' dans la définition de la classe' Bar', il le change en 'self._Bar__baz'. Quand il voit 'self .__ baz' dans la définition de la classe' Foo', il le change en 'self._Foo__baz'. L'idée ici est que 'self .__ baz' dans' Foo' peut être distinct de 'self .__ baz' dans' Bar'. – mgilson

+0

Donc en fait quand il appelle 'super (Bar, self).__init __() 'L'objet Bar de la classe enfant a ** deux ** attributs l'un est' _Bar__baz' (parce qu'il fait '.__ baz = 21' dans la méthode init de la classe enfant) et l'autre est' _Foo__baz' de la classe parente **? * * Attendu qu'en cas d'erreur (s'il n'appelle pas 'super (Bar, self) .__ init __()') L'objet Bar n'a qu'un seul attribut '_Bar__baz' **? ** –

3

Lorsque vous nommez des variables avec un double trait de soulignement comme dans python, le nom du membre sera obscurci. La déclaration __baz vous donne un membre _Bar__baz.

class Bar(Foo): 
def __init__(self): 
    #super(Bar, self).__init__() 
    self.__baz = 21 
def bar(self): 
    print self._Bar__baz 

x = Bar() 
x.bar() 
>>> 21 
+0

vous avez changé la définition de la fonction 'bar'. Je voudrais savoir pourquoi cela fonctionne quand le super appel est fait, comme je l'ai fait dans mon edit –

+0

+ comme vous avez ajouté un truc qui est utile pour moi, mais n'est-il pas mal d'utiliser explicitement '_Bar__baz' **? * * –

Questions connexes