Herencia simple versus herencia múltiple
Como ya sabes, no hay obstáculos para usar la herencia múltiple en Python. Puedes derivar cualquier clase nueva de más de una clase definida previamente.
Solo hay un "pero". El hecho de que puedas hacerlo no significa que tengas que hacerlo.
No olvides que:
- Una sola clase de herencia siempre es más simple, segura y fácil de entender y mantener.
- La herencia múltiple siempre es arriesgada, ya que tienes muchas más oportunidades de cometer un error al identificar estas partes de las superclases que influirán efectivamente en la nueva clase.
- La herencia múltiple puede hacer que la anulación sea extremadamente difícil; además, el emplear la función
super()
se vuelve ambiguo. - La herencia múltiple viola el principio de responsabilidad única (mas detalles aquí: https://en.wikipedia.org/wiki/Single_responsibility_principle) ya que forma una nueva clase de dos (o más) clases que no saben nada una de la otra.
- Sugerimos encarecidamente la herencia múltiple como la última de todas las posibles soluciones: si realmente necesitas las diferentes funcionalidades que ofrecen las diferentes clases, la composición puede ser una mejor alternativa.
Diamantes y porque no los quieres
El espectro de problemas que posiblemente provienen de la herencia múltiple se ilustra mediante un problema clásico denominado problema de diamantes. El nombre refleja la forma del diagrama de herencia: echa un vistazo a la imagen.
- Existe la superclase superior nombrada A.
- Aquí hay dos subclases derivadas de A - B y C.
- Y también está la subclase inferior llamada D, derivada de B y C (o C y B, ya que estas dos variantes significan cosas diferentes en Python).
¿Puedes ver el diamante allí?
A Python, sin embargo, no le gustan los diamantes, y no te permitirá implementar algo como esto. Si intentas construir una jerarquía como esta:
class A:
pass
class B(A):
pass
class C(A):
pass
class D(A, B):
pass
d = D()
Obtendrás una excepción TypeError, junto con el siguiente mensaje:
Cannot create a consistent method resolution
order (MRO) for bases B, A
Donde MRO
significa Method Resolution Order. Este es el algoritmo que Python utiliza para buscar el árbol de herencia y encontrar los métodos necesarios.
Los diamantes son preciosos y valiosos ... pero no en la programación. Evítalos por tu propio bien.