Lecciones del módulo (2/4)
Herencia
La herencia (inheritance) permite crear una nueva clase (la subclase) que hereda los atributos y métodos de una clase existente (la clase base), y puede extenderlos o sobrescribirlos (override).
Sintaxis básica
class Animale:
def __init__(self, nome):
self.nome = nome
def saluta(self):
return f"{self.nome} fa un verso"
class Cane(Animale): # Cane HEREDA de Animale
def saluta(self): # SOBRESCRITURA del método (override)
return f"{self.nome} dice WOOF!"
a = Animale("X")
c = Cane("Fido")
a.saluta() # 'X fa un verso'
c.saluta() # 'Fido dice WOOF!'Cane hereda __init__ de Animale sin necesidad de volver a escribirlo.
super(): llamar al método base
Cuando quieres extender un método base (no reemplazarlo por completo), usa
super():
class Animale:
def __init__(self, nome):
self.nome = nome
class Cane(Animale):
def __init__(self, nome, razza):
super().__init__(nome) # delega a la clase base
self.razza = razza
c = Cane("Fido", "Labrador")
c.nome # 'Fido'
c.razza # 'Labrador'isinstance: comprobación de tipo
isinstance(c, Cane) # True
isinstance(c, Animale) # True (también la clase base)
isinstance(c, str) # Falseisinstance(x, ClaseBase) también reconoce a todas las subclases: esto es lo que hace
que la herencia sea útil para el polimorfismo.
animali = [Cane("Fido", "X"), Animale("Pippo")]
for a in animali:
print(a.saluta()) # cada objeto responde a su maneraMRO (Method Resolution Order) — resumen
Cuando tienes herencia múltiple, Python decide en qué orden buscar un método siguiendo el MRO, calculado con el algoritmo C3. Para el 95% de los casos basta con saber:
- busca primero en la instancia,
- luego en su clase,
- luego en las clases base en el orden de declaración.
Cane.__mro__
# (<class 'Cane'>, <class 'Animale'>, <class 'object'>)object es la raíz de todas las clases en Python 3.
Pruébalo tú
Dada `class Vehicle: def __init__(self, brand): self.brand = brand`, define `Car(Vehicle)` con __init__(self, brand, model) que llame a super().__init__ y guarde self.model. Crea `a = Car('Fiat', '500')` y evalúa `(a.brand, a.model)`.
Mostrar pista
super().__init__(brand) y luego self.model = model.
Solución disponible después de 3 intentos
Ejercicio de repaso
Define `class Shape: def area(self): return 0` y `class Square(Shape)` con __init__(self, side) y area() que devuelva side * side. Crea `q = Square(5)` y evalúa la tupla `(q.area(), isinstance(q, Shape))`.
Mostrar pista
self.side * self.side.
Solución disponible después de 3 intentos
Desafío adicional
Crea una clase `Square` que herede de la clase `Rectangle` (definida a continuación). El constructor de `Square` debe tomar un único parámetro `side` y pasarlo a `super().__init__(side, side)`. Instancia un cuadrado con lado `6` en `sq` y evalúa `sq.area()`.
Mostrar pista
Declara la clase Square(Rectangle): y llama a super().__init__(side, side) en el constructor.
Solución disponible después de 3 intentos