Dziedziczenie i metoda init w Pythonie

99

Jestem początkującym pytonem. Nie rozumiem dziedziczenia i __init__().

class Num:
    def __init__(self,num):
        self.n1 = num

class Num2(Num):
    def show(self):
        print self.n1

mynumber = Num2(8)
mynumber.show()

WYNIK: 8

To jest wporządku. Ale mogę wymienić Num2z

class Num2(Num):
    def __init__(self,num):
        self.n2 = num*2
    def show(self):
        print self.n1,self.n2

WYNIK: Error. Num2 has no attribute "n1".

W takim przypadku, jak można Num2uzyskać dostęp n1?

Yugo Kamo
źródło

Odpowiedzi:

152

W pierwszej sytuacji Num2jest to rozszerzenie klasy, Numa ponieważ nie redefiniujesz metody specjalnej o nazwie __init__()w Num2, jest ona dziedziczona z Num.

Gdy klasa definiuje __init__() metodę, instancja klasy jest automatycznie wywoływana __init__()dla nowo utworzonej instancji klasy.

W drugiej sytuacji, ponieważ przedefiniowujesz __init__()w Num2, musisz jawnie wywołać tę z superklasy ( Num), jeśli chcesz rozszerzyć jej zachowanie.

class Num2(Num):
    def __init__(self,num):
        Num.__init__(self,num)
        self.n2 = num*2
Mario Duarte
źródło
27
Twój cytat nie jest wystarczający, aby wyjaśnić, dlaczego, gdy nie definiujesz __init__metody w klasie pochodnej, jest ona dziedziczona. Dzieje się tak, ponieważ „jeśli żądany atrybut nie zostanie znaleziony w klasie, wyszukiwanie będzie kontynuowane w celu wyszukania klasy bazowej”. (doc)
eyquem,
6
Przepraszam ... tak w zasadzie działa dziedziczenie ... jeśli dziedziczysz klasę, otrzymujesz cały pakiet, więc wszystko w nadklasie istnieje w podklasie. Ale jeśli przedefiniujesz metodę, zostanie ona zastąpiona ... to właśnie jest w twoim kodzie.
coya
5
@ mario-duarte jakiś powód, dla którego byłoby to lepsze niż super(Num2, self).__init__(num)?
guival
1
Właśnie przełączyłem się z rozwiązania zaproponowanego w tej odpowiedzi na używanie super, a mój program ładuje się teraz o kilka sekund szybciej. Nie mam pojęcia dlaczego.
Guimoute
superma być pomocny w przypadku dziedziczenia wielokrotnego. W przypadku pojedynczego spadku korzyści nie są oczywiste.
Johann Bzh
4

Ponieważ nie dzwonisz Num.__init__, pole „n1” nigdy nie zostanie utworzone. Zadzwoń, a wtedy będzie.

Danny Milosavljevic
źródło
4

Prosta zmiana w klasie Num2, taka jak ta:

super().__init__(num) 

Działa w python3.

class Num:
        def __init__(self,num):
                self.n1 = num

class Num2(Num):
        def __init__(self,num):
                super().__init__(num)
                self.n2 = num*2
        def show(self):
                print (self.n1,self.n2)

mynumber = Num2(8)
mynumber.show()
Sacchit Jaiswal
źródło
2
Dlatego uwielbiam przepełnienie stosów. Chociaż to nie jest odpowiedź na pytanie, jest pomocna. Czasami odpowiedzi publikowane przez ludzi są odpowiedziami na pytanie, które ludzie powinni byli zadawać. Dziękuję Ci!
Glen Thompson,