Herencia en Python: super(), sobreescribir métodos y herencia múltiple

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.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP