La herencia permite que una clase hija reutilice y extienda el comportamiento de una clase base. Python soporta herencia simple y múltiple, y tiene un algoritmo —el MRO— para resolver el orden en que se buscan los métodos cuando hay varias clases base.
Herencia básica y super()
class Animal:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def describir(self):
return f"{self.nombre} ({self.edad} años)"
def hablar(self):
return "..."
class Perro(Animal):
def __init__(self, nombre, edad, raza):
super().__init__(nombre, edad) # delega al __init__ del padre
self.raza = raza
def hablar(self): # sobreescribe el método del padre
return "¡Guau!"
def describir(self):
base = super().describir() # llama al método del padre
return f"{base}, raza: {self.raza}"
rex = Perro("Rex", 3, "Labrador")
print(rex.describir()) # Rex (3 años), raza: Labrador
print(rex.hablar()) # ¡Guau!
isinstance() e issubclass()
print(isinstance(rex, Perro)) # True print(isinstance(rex, Animal)) # True — hereda de Animal print(isinstance(rex, str)) # False print(issubclass(Perro, Animal)) # True print(issubclass(Animal, object)) # True — todo hereda de object
Herencia múltiple y MRO
Python resuelve el orden de búsqueda de métodos con el algoritmo C3 linearization (MRO). Puedes consultarlo con __mro__ o mro():
class Volador:
def mover(self):
return "volando"
class Nadador:
def mover(self):
return "nadando"
class Pato(Volador, Nadador):
pass
donald = Pato()
print(donald.mover()) # 'volando' — Volador va primero en el MRO
print(Pato.__mro__)
# (, , , )
El patrón mixin
Un mixin es una clase pequeña que añade una funcionalidad especÃfica sin representar una entidad del dominio. No está diseñada para usarse sola, sino para combinarse:
class JsonMixin:
"""Serializa a JSON cualquier clase con __dict__."""
def to_json(self):
import json
return json.dumps(self.__dict__, ensure_ascii=False, default=str)
class LogMixin:
"""Añade un método de log con nombre de clase automático."""
def log(self, mensaje):
print(f"[{self.__class__.__name__}] {mensaje}")
class Usuario(JsonMixin, LogMixin):
def __init__(self, nombre, email):
self.nombre = nombre
self.email = email
u = Usuario("Ana", "[email protected]")
print(u.to_json()) # {"nombre": "Ana", "email": "[email protected]"}
u.log("Creado") # [Usuario] Creado
Métodos abstractos: forzar implementación en subclases
from abc import ABC, abstractmethod
class FormaPago(ABC):
@abstractmethod
def cobrar(self, importe):
pass
@abstractmethod
def nombre(self):
pass
class Tarjeta(FormaPago):
def cobrar(self, importe):
return f"Cargo de {importe}€ en tarjeta"
def nombre(self):
return "Tarjeta de crédito"
# FormaPago() # TypeError: no se puede instanciar clase abstracta
t = Tarjeta()
print(t.cobrar(49.99)) # Cargo de 49.99€ en tarjeta
Usa super() siempre que extiendas __init__ para no olvidar inicializar la clase base. Prefiere mixins a herencia profunda cuando necesites añadir comportamiento transversal. Y consulta el MRO con ClaseHija.__mro__ si un método no se resuelve como esperas.
