Método de herança e init em Python

98

Eu sou o iniciante do python. Eu não consigo entender herança e __init__().

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

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

mynumber = Num2(8)
mynumber.show()

RESULTADO: 8

Isso está bem. Mas eu substituo Num2por

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

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

Nesse caso, como pode Num2acessar n1?

Yugo Kamo
fonte

Respostas:

151

Na primeira situação, Num2está estendendo a classe Nume, como você não está redefinindo o método especial nomeado __init__()em Num2, ele é herdado de Num.

Quando uma classe define um __init__() método, a instanciação da classe invoca automaticamente a instância da classe __init__()recém-criada.

Na segunda situação, como você está redefinindo __init__()em, Num2você precisa chamar explicitamente aquele na superclasse ( Num) se quiser estender seu comportamento.

class Num2(Num):
    def __init__(self,num):
        Num.__init__(self,num)
        self.n2 = num*2
Mario duarte
fonte
27
Sua citação não é suficiente para explicar por que, ao não definir um __init__método em uma classe derivada, ele é herdado. É porque "se um atributo solicitado não for encontrado na classe, a pesquisa prossegue para procurar na classe base." (doc)
eyquem
6
Sinto muito ... é basicamente assim que a herança funciona ... se você herda uma classe, obtém o pacote inteiro, então, tudo na superclasse existe na subclasse. Mas, se você redefinir um método, ele é sobrescrito ... isso é o que está em seu código.
coya
5
@ mario-duarte alguma razão pela qual isso seria melhor do que super(Num2, self).__init__(num)?
guival
1
Acabei de mudar da solução proposta nesta resposta para usar super, e meu programa agora carrega alguns segundos mais rápido. Não faço ideia do porquê.
Guimoute
superdeve ser útil ao usar herança múltipla. Para herança única, seus benefícios não são óbvios.
Johann Bzh
4

Como você não chama Num.__init__, o campo "n1" nunca é criado. Ligue e então estará lá.

Danny Milosavljevic
fonte
4

Uma mudança simples na classe Num2 como esta:

super().__init__(num) 

Funciona em 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
fonte
2
É por isso que adoro stackoverflow. Mesmo que essa não seja a resposta à pergunta, é útil. Às vezes, as respostas que as pessoas postam são as respostas às perguntas que as pessoas deveriam estar fazendo. Obrigado!
Glen Thompson