Метод наследования и инициализации в Python

94

Я новичок в питоне. Я не могу понять наследование и __init__().

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

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

mynumber = Num2(8)
mynumber.show()

РЕЗУЛЬТАТ: 8

Хорошо. Но я заменяю Num2на

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

РЕЗУЛЬТАТ: Error. Num2 has no attribute "n1".

В таком случае как получить Num2доступ n1?

Юго Камо
источник

Ответы:

148

В первой ситуации Num2это расширение класса, Numи поскольку вы не переопределяете специальный метод с именем __init__()in Num2, он наследуется от Num.

Когда класс определяет __init__() метод, создание экземпляра класса автоматически вызывается __init__()для вновь созданного экземпляра класса.

Во втором случае, так как вы пересматриваете __init__()в Num2вам нужно явно вызвать один в супер класс ( Num) , если вы хотите продлить свое поведение.

class Num2(Num):
    def __init__(self,num):
        Num.__init__(self,num)
        self.n2 = num*2
Марио Дуарте
источник
23
Вашей цитаты недостаточно, чтобы объяснить, почему, когда __init__метод не определяется в производном классе, он наследуется. Это потому, что «если запрошенный атрибут не найден в классе, поиск продолжается в базовом классе». (doc)
eyquem
5
Мне очень жаль ... это в основном принцип работы наследования ... если вы наследуете класс, вы получаете весь пакет, поэтому все в суперклассе существует в подклассе. Но если вы переопределите метод, он переопределится ... это то, что происходит в вашем коде.
coya
4
@ mario-duarte, почему это лучше super(Num2, self).__init__(num)?
guival
1
Я только что переключился с решения, предложенного в этом ответе, на использование super, и теперь моя программа загружается на несколько секунд быстрее. Понятия не имею почему.
Guimoute
superдолжен быть полезен при использовании множественного наследования. Для единоличного наследования его преимущества не очевидны.
Иоганн Бж
4

Поскольку вы не вызываете Num.__init__, поле «n1» никогда не создается. Назовите это, и тогда оно будет там.

Дэнни Милосавлевич
источник
3

Простое изменение в классе Num2, например:

super().__init__(num) 

Он работает в 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()
Сакчит Джайсвал
источник
1
Вот почему я люблю stackoverflow. Хотя это не ответ на вопрос, это полезно. Иногда ответы, которые публикуют люди, являются ответами на вопрос, который люди должны были задать. Спасибо!
Глен Томпсон,