Python es uno de los pocos lenguajes modernos que permite la herencia múltiple. Aunque es una característica poderosa, también es una de las que más confusión genera, especialmente cuando dos clases padre tienen métodos con el mismo nombre.
En este post vamos a desmitificar cómo Python decide a qué método llamar y cuándo es mejor evitar esta técnica.
¿Qué es la Herencia Múltiple?
A diferencia de Java o C#, donde una clase solo puede tener un padre directo, en Python una clase puede heredar de múltiples clases. Esto nos permite “mezclar” funcionalidades de distintos orígenes.
class Reloj:
def mostrar_hora(self):
print("Son las 12:00")
class Calendario:
def mostrar_fecha(self):
print("Hoy es 15 de marzo")
class Smartwatch(Reloj, Calendario):
pass
reloj = Smartwatch()
reloj.mostrar_hora() # Viene de Reloj
reloj.mostrar_fecha() # Viene de Calendario
El Problema del Diamante y el MRO
El problema surge cuando dos clases padre tienen un método con el mismo nombre. ¿Cuál debería ejecutar Python? Para resolver esto, Python utiliza el MRO (Method Resolution Order).
El MRO es el algoritmo que define el orden de búsqueda de métodos. Python sigue una regla de “izquierda a derecha” y de “abajo hacia arriba”, pero manteniendo una jerarquía coherente.
Figura 1: El problema del diamante en herencia múltiple
class A:
def saludar(self):
print("Hola desde A")
class B(A):
def saludar(self):
print("Hola desde B")
class C(A):
def saludar(self):
print("Hola desde C")
class D(B, C):
pass
objeto = D()
objeto.saludar() # ¿Qué imprimirá?
En este caso, imprimirá “Hola desde B” porque B aparece primero en la lista de herencia de la clase D.
Tip: Puedes consultar el orden exacto de búsqueda de cualquier clase usando el atributo
__mro__o el método.mro(). Por ejemplo:print(D.mro()).
Herencia vs. Composición
Aunque la herencia múltiple es posible, muchos desarrolladores senior recomiendan usarla con extrema precaución. Una alternativa más limpia suele ser la Composición.
La composición consiste en tener instancias de otras clases dentro de tu clase, en lugar de heredar de ellas.
class Smartwatch:
def __init__(self):
self.reloj = Reloj()
self.calendario = Calendario()
def mostrar_todo(self):
self.reloj.mostrar_hora()
self.calendario.mostrar_fecha()
Regla de oro: Usa herencia solo si hay una relación clara de “es un”. Si solo necesitas usar una funcionalidad de otra clase, usa composición (“tiene un”).
Conclusión: ¿Cuándo usar herencia múltiple?
- Mixins: Cuando quieres añadir pequeñas funcionalidades opcionales a muchas clases distintas.
- Interfaces: Cuando una clase debe cumplir con varios contratos de comportamiento.
- Jerarquías claras: Cuando no hay riesgo de colisión de nombres o ambigüedad.
Recuerda siempre revisar el mro() si notas comportamientos extraños en tu jerarquía de clases.
Comentarios