2012-04-22 15 views
14

Mam następujące klasy bazowej i podklasy:Python klasy dziedziczenie: AttributeError: „[Podklasa]” obiekt ma atrybut „xxx”

class Event(object): 
    def __init__(self, sr1=None, nr1=None, foo=None, foobar=None, nr2=None, sr2=None, flag = False): 
     self.sr1 = sr1 
     self.nr1 = nr1 
     self.foo = foo 
     self.foobar = foobar 
     self.nr2 = nr2 
     self.sr2 = sr2 
     self.flag = flag 
     self.state = STATE_NON_EVENT 

    def state_name(self): 
     return STATE_NAMES[self.state] 

    def __repr__(self): 
     return 'Non event' 



# Event class wrappers to provide syntatic sugar 
class TypeTwoEvent(Event): 
    def __init__(self, level=None): 
     self.sr1 = level 
     self.state = STATE_EVENT_TWO 

    def __repr__(self): 
     return "Type Two event (Level @: {0:.2f})".format(self.sr1) 

dalej w moim kodu, mam kontroli instancję Klasa TypeTwoEvent, sprawdzając pole, które wiem, istnieje w klasie bazowej - oczekiwałem, że będzie domyślnie wartość Brak. Jednak mój kod pojawia się następujący wyjątek:

AttributeError: 'TypeTwoEvent' object has no attribute 'foobar'

Byłem pod wrażeniem, że pola klasy bazowej będą dziedziczone przez klasy sub i tworzenia instancji klasy sub będzie instancję klasy bazowej (a więc wywołaj jego konstruktora) ...

Czego mi tu brakuje? Dlaczego TypeTwoEvent nie ma atrybutu foobar - kiedy klasa bazowa, z której pochodzi, ma atrybut foobar?

+1

Jak wspomniano poniżej, musisz wyraźnie zaznaczyć, że chcesz również zainicjować superklasy. Ale uważaj__: jeśli masz jakieś wielokrotne dziedziczenie, to zrobienie tego staje się bardzo delikatne. – katrielalex

Odpowiedz

15

Twój podklasy powinno być:

class TypeTwoEvent(Event): 

    def __init__(self, level=None, *args, **kwargs): 
     super(TypeTwoEvent, self).__init__(*args, **kwargs) 
     self.sr1 = level 
     self.state = STATE_EVENT_TWO 

    def __repr__(self): 
     return "Type Two event (Level @: {0:.2f})".format(self.sr1) 

Bo zastąpić metodę __init__, więc trzeba wywołać metodę nadrzędnej, jeśli chcesz zachowanie rodzica wydarzy.

Pamiętaj, że __init__ nie jest specjalną metodą unieszkodliwiającą swoją dziwną nazwę. Jest to metoda automatycznie wywoływana po utworzeniu obiektu. W przeciwnym razie jest to zwykła metoda i obowiązują zwykłe zasady dziedziczenia.

super(ClassName, self).__init__(arguments, that, goes, to, parents) 

jest składnią do wywołania rodzicielskiej wersji metody.

Dla *args i **kwargs, to właśnie gwarantuje nam złapać wszystkie dodatkowe argumenty przekazywane do __init__ i przekazać je do metody nadrzędnej, jak podpis sposób dziecko nie zrobił to i rodzic muszą te argumenty do pracy.

+0

Dzięki za zmianę Chris. Jestem Francuzem i często wprowadzam to zamieszanie między "to jest" i "jego". Nie żebym mieszał znaczenia, ale nauczyłem się języka mówiącego, dlatego jest on (:-)) łatwy do wymiany dźwięku na inny w mojej głowie. –

1

Należy wywołać metodę __init__ klasy bazowej z metody odziedziczonej klasy __init__.

Zobacz, jak to zrobić: here.

2

Po utworzeniu instancji zostaje wywołana metoda __init__. W tym przypadku jest to TypeTwoEvent.__init__. Metody nadklasy nie zostaną wywołane automatycznie, ponieważ byłoby to niezmiernie kłopotliwe.

Należy zadzwonić pod numer Event.__init__(self, ...) z TypeTwoEvent.__init__ (lub użyć super, ale jeśli nie jesteś zaznajomiony z tym, przeczytaj go najpierw, aby wiedzieć, co robisz).

2

Zastępujesz konstruktora (__init__) klasy nadrzędnej. Aby go rozszerzyć, musisz jawnie wywołać konstruktora obiektu nadrzędnego za pomocą wywołania super().

class TypeTwoEvent(Event): 
    def __init__(self, level=None, **kwargs): 
     # the super call to set the attributes in the parent class 
     super(TypeTwoEvent, self).__init__(**kwargs) 
     # now, extend other attributes 
     self.sr1 = level 
     self.state = STATE_EVENT_TWO 

Zauważ, że wywołanie super jest nie zawsze na szczycie swojej metody w podklasie __init__. Jego lokalizacja zależy od twojej sytuacji i logiki.

0

Miałem problem z tym również, ale włożyłem super().__init__() na dole mojej klasy pochodnej i dlatego to nie działa. Ponieważ próbuję użyć atrybutów, które nie zostały zainicjalizowane.

Powiązane problemy