Herencia y método init en Python

94

Soy un principiante de Python. No puedo entender la herencia y __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

Esto esta bien. Pero reemplazo Num2con

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".

En este caso, ¿cómo puedo Num2acceder n1?

Yugo Kamo
fuente

Respuestas:

148

En la primera situación, Num2está extendiendo la clase Numy, dado que no está redefiniendo el método especial nombrado __init__()en Num2, se hereda de Num.

Cuando una clase define un __init__() método, la instanciación de clase invoca automáticamente la instancia de clase __init__()recién creada.

En la segunda situación, dado que está redefiniendo __init__()en Num2, debe llamar explícitamente al de la superclase ( Num) si desea extender su comportamiento.

class Num2(Num):
    def __init__(self,num):
        Num.__init__(self,num)
        self.n2 = num*2
Mario Duarte
fuente
23
Su cita no es suficiente para explicar por qué, cuando no se define un __init__método en una clase derivada, se hereda. Es porque "si un atributo solicitado no se encuentra en la clase, la búsqueda procede a buscar en la clase base". (doc)
eyquem
5
Lo siento ... así es básicamente como funciona la herencia ... si heredas una clase, obtienes el paquete completo, entonces, todo en la superclase existe en la subclase. Pero, si redefine un método, se anula ... eso es lo que pasa en su código.
coya
4
@ mario-duarte alguna razón por la que esto sería mejor que super(Num2, self).__init__(num)?
guival
1
Acabo de cambiar de la solución propuesta en esta respuesta al uso super, y mi programa ahora se carga unos segundos más rápido. No tengo idea de por qué.
Guimoute
superse supone que es útil cuando se usa herencia múltiple. Para la herencia única, sus beneficios no son obvios.
Johann Bzh
4

Como no llama Num.__init__, el campo "n1" nunca se crea. Llámalo y luego estará allí.

Danny Milosavljevic
fuente
3

Un simple cambio en la clase Num2 como este:

super().__init__(num) 

Funciona en 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
fuente
1
Por eso me encanta stackoverflow. Aunque esta no es la respuesta a la pregunta, es útil. A veces, las respuestas que la gente publica son las respuestas a la pregunta que la gente debería haberse hecho. ¡Gracias!
Glen Thompson