1

Antes de nada, agradeceros por la ayuda.

Veréis, tengo el siguiente código:

class Animal():

    def __init__(self, raza, edad, pelaje, tamano): # Características propias de un animal.

        # Con self crearemos una instancia independiente para cada animal.
        self.raza = raza 
        self.edad = edad
        self.pelaje = pelaje
        self.tamano = tamano

        RAZA = "perro" # Constante invariable, que además compartirá todas las instancias de la clase animal. Es decir, una variable para todas las instancias.


    # COMPORTAMIENTOS ¿Qué es capaz de hacer nuestro objeto perro?
    def comer(self, t_hambre):
        self.t_hambre = t_hambre

        if self.t_hambre:
            print(self.nombre, " está comiendo.")
        else:
            print(self.nombre, " no parece tener hambre ahora.")


    def jugar(self):
        print("Estás jugando con ", self.nombre)


    def __necesidades(self):
        print(self.nombre, " ha hecho sus necesidades")


class Mascota(Animal):
    def __init__(self, nombre, dueno, raza, edad, pelaje, tamano):
        super().__init__(raza, edad, pelaje, tamano)
        self.nombre = nombre
        self.dueno = dueno


tobi = Mascota("Tobi", "Juan", "Doberman", 0, "Marrón", "25cm")

tobi.comer(True)

El cual solo estoy haciedo a modo orietativo para aprender un poco de POO en python. Bueno, la cuestión es que me he atascado en el alcande que tiene una variable en python, porque ¿Cómo puede ser que una variable creada en una clase que herada de Animal(), en este caso, self.nombre de la clase mascota, sea usada en el método comer, es algo que no entiendo.

Muchas gracias.

Man
  • 137
  • 6

1 Answers1

1

self.nombre no es un atributo de instancia de la clase Animal, es un atributo de instancia de la clase hija Mascota. Tu duda viene porque observas que esta variable se puede usar en el método de instancia comer que es heredado de la clase Animal la cual no define el atributo.

Pero realmente no hay nada especial en ello, el atributo se puede usar en el método de instancia de la clase Mascota pero no se puede usar en el método de instancia de la clase Animal. Si intentas llamar al método comer de Animal tendrás una bonita excepción:

 >>> animal = Animal("Doberman", 0, "Marrón", "25cm")
 >>> animal.comer(True)

 Exception has occurred: AttributeError
     'Animal' object has no attribute 'nombre'

Mascota hereda de Animal todos sus métodos y atributos, lo que incluye el método comer. Ademas implementa el atributo de instancia nombre por lo que puede ser usado en su método comer.

Realmente el problema es que tu método comer (lo mismo ocurre con los otros) no está técnicamente correctamente implementado en Animal, simplemente porque intenta hacer uso de un atributo que no existe. Ninguno de los métodos de Animal excepto el inicializador se pueden llamar por esta razón. Si Animal no va a tener nombre no deberías usarlo en su método.

No obstante hay casos en los que esta forma de actuar está justificada, por ejemplo en el patrón de diseño de "método de la plantilla" (template method design pattern).

Una pequeña aclaración, RAZA no es una variable común a todas las instancias, RAZA es una variable local al método init y deja de existir en el mismo momento que el inicializador retorna. Una vez inicializada la clase es imposible acceder a la variable RAZA desde ningún lado. El concepto que defines en el comentario:

"compartirá todas las instancias de la clase animal. Es decir, una variable para todas las instancias"

es precisamente lo que es un atributo de clase, pero este ha de ser definido usando una referencia a la clase (Animal.RAZA = "perro" o en un método de clase) o bien fuera de cualquier método:

class Animal:
    RAZA = "perro"

mirate la siguiente pregunta para más información:

FJSevilla
  • 55,603
  • 7
  • 35
  • 58
  • Muchas gracias por la aclaración. Le echaré un vistazo al link que me has pasado! – Man Jul 15 '19 at 20:47