2013-09-27 12 views
8

Mam następujący kod.Dlaczego klasa podrzędna nie dziedziczy metody z klasy nadrzędnej w pythonie w tym przykładzie?

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() 

otrzymuję ten błąd:

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' 

dlaczego jest metoda foo nie odziedziczyła w Bar.

EDYTOWANIE: Działa dobrze, jeśli zadzwonisz super, który jest skomentowany.

+3

Nie jestem pewien, ale czy nie dlatego, że zmienna __varia jest specjalną zmienną? http://stackoverflow.com/a/1301369/2537322 – meyer9

+0

Co ciekawsze, dlaczego to * działa *, jeśli wywołasz 'super()'? –

+0

Brak odpowiedzi, ale dodaje więcej szczegółów - jeśli zmienisz ją z '__baz' na' baz', oba wywołania wypiszą 21. Jeśli wywołasz 'super()' i opuścisz jako '__baz', wydrukują' 40' i '21' odpowiednio. –

Odpowiedz

7

Podwójne atrybuty podkreślenia mają swoje nazwy zniekształcone na podstawie prądu /zawierający nazw. W funkcji foo obecna przestrzeń nazw to Foo, więc gdy pyton wyszuka self.__baz, będzie szukał ze względu na schemat wymazywania nazwy. Ponieważ nigdzie w Foo nie ustawiono atrybutu __baz, klasa nie ma atrybutu _Foo__baz (ma atrybut _Bar__baz od ustawienia self.__baz w metodzie z zakresu Bar).

Oczywiście, jak już zapewne zauważyliście, jeśli zadzwonisz Foo.__init__(self) w Baz.__init__ (bezpośrednio lub poprzez super), zobaczysz problem odejść bo Foo.__init__ zestawy __baz (tj _Foo__baz).

+0

, więc metoda foo nie jest dziedziczona poprawnie? Jestem trochę zdezorientowany co do tego, co się tutaj dzieje ... –

+0

@ user1988876 - metoda 'foo' * jest * dziedziczona. Ale gdy go nazwiesz, atrybut, do którego próbuje uzyskać dostęp, jest * brak *. Kiedy Python widzi 'self .__ baz' w definicji klasy' Bar', zmienia ją na 'self._Bar__baz'. Kiedy widzi 'self .__ baz' w definicji klasy' Foo', zmienia ją na 'self._Foo__baz'. Cały pomysł polega na tym, że 'self .__ baz' wewnątrz' Foo' może różnić się od 'self .__ baz' wewnątrz' Bar'. – mgilson

+0

Więc tak naprawdę, kiedy nazywa się 'super (Bar, self).__init __() 'child class Obiekt Bar ma ** dwa ** atrybuty jeden to' _Bar__baz' (ponieważ robi 'self .__ baz = 21' w metodzie init klasy potomnej), a drugi to' _Foo__baz' z klasy rodzica **? * * W przypadku błędu (jeśli nie nazywa się 'super (Bar, self) .__ init __()') Obiekt Bar ma tylko jeden atrybut, który jest "_Bar__baz' **? ** –

3

Gdy nazwiesz zmienne z podwójnym podkreśleniem w pythonie, nazwa elementu zostanie zaciemniona. Zgłaszanie __baz daje użytkownikowi _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

zmieniłeś definicję funkcji 'bar'. Chciałbym wiedzieć, dlaczego działa, gdy super wywołanie jest wykonane, jak zrobiłem w mojej edycji –

+0

+, gdy dodałeś lewę, która jest dla mnie przydatna, ale czy nie jest złą praktyką użycie '_Bar__baz' jawnie **? * * –

Powiązane problemy