Herencia vs composición en Python: decisiones de diseño que escalan

Aprende cuándo heredar y cuándo componer objetos para reducir acoplamiento, evitar jerarquías frágiles y mantener flexibilidad en sistemas reales.

La herencia expresa relación `es-un` (`Admin` es un `Usuario`), mientras composición expresa `tiene-un` (`Pedido` tiene un `CalculadorImpuestos`).

Usar herencia por comodidad suele crear jerarquías rígidas y difíciles de cambiar.

La composición permite reemplazar comportamientos sin tocar la clase principal.

En Python profesional, la regla práctica frecuente es: prefiere composición salvo que la herencia sea semánticamente clara.

  • Úsala cuando exista una relación de tipo real y estable.
  • Si una subclase rompe reglas de la clase base o ignora parte de su contrato, la jerarquía está mal diseñada.
  • La herencia puede ser útil para compartir comportamiento común en un dominio bien definido.
  • Evita cadenas profundas de herencia; complican lectura y depuración.
  • Una clase delega responsabilidades en otras piezas especializadas.

1) Herencia: cuándo sí tiene sentido

Úsala cuando exista una relación de tipo real y estable.

Si una subclase rompe reglas de la clase base o ignora parte de su contrato, la jerarquía está mal diseñada.

La herencia puede ser útil para compartir comportamiento común en un dominio bien definido.

Evita cadenas profundas de herencia; complican lectura y depuración.

2) Composición: flexibilidad por colaboración

Una clase delega responsabilidades en otras piezas especializadas.

Con composición puedes cambiar una dependencia por otra implementación sin reescribir todo el objeto principal.

Este patrón favorece testeo: puedes inyectar dobles de prueba (mocks/fakes) fácilmente.

También ayuda a mantener clases pequeñas y cohesionadas.

3) Criterios prácticos de decisión

Elige patrón según estabilidad semántica y necesidad de variación.

Muchos problemas de mantenimiento vienen de herencias prematuras que parecían elegantes al principio.

Componer objetos con dependencias explícitas hace más fácil evolucionar arquitectura sin romper contratos previos.

Tu objetivo no es usar un patrón "bonito", sino reducir coste de cambio futuro.

  • Si la relación es naturalmente de tipo (`es-un`) y estable, herencia puede ser válida.
  • Si esperas cambiar comportamientos frecuentemente, composición suele ser mejor.
  • Prefiere interfaces simples entre componentes para desacoplar capas.
  • Si una subclase empieza a desactivar lógica base, revisa diseño: probablemente necesitas composición.
Python
14

Herencia vs composición en Python: decisiones de diseño que escalan

Aprende cuándo heredar y cuándo componer objetos para reducir acoplamiento, evitar jerarquías frágiles y mantener flexibilidad en sistemas reales.

Código del tema: class Usuario: pass

📘 Teoría

1) Herencia: cuándo sí tiene sentido

Úsala cuando exista una relación de tipo real y estable.

1

Si una subclase rompe reglas de la clase base o ignora parte de su contrato, la jerarquía está mal diseñada.

2

La herencia puede ser útil para compartir comportamiento común en un dominio bien definido.

3

Evita cadenas profundas de herencia; complican lectura y depuración.

Herencia simple con sobrescritura controlada
class Usuario:
    def permisos(self) -> set[str]:
        return {'leer'}


class Admin(Usuario):
    def permisos(self) -> set[str]:
        return super().permisos() | {'editar', 'borrar'}

2) Composición: flexibilidad por colaboración

Una clase delega responsabilidades en otras piezas especializadas.

Con composición puedes cambiar una dependencia por otra implementación sin reescribir todo el objeto principal.

Este patrón favorece testeo: puedes inyectar dobles de prueba (mocks/fakes) fácilmente.

También ayuda a mantener clases pequeñas y cohesionadas.

1

Componente de motor

La lógica de arranque vive en `Motor`.

2

Objeto compuesto

`Coche` delega en `Motor`.

3) Criterios prácticos de decisión

Elige patrón según estabilidad semántica y necesidad de variación.

Muchos problemas de mantenimiento vienen de herencias prematuras que parecían elegantes al principio.

Componer objetos con dependencias explícitas hace más fácil evolucionar arquitectura sin romper contratos previos.

Tu objetivo no es usar un patrón "bonito", sino reducir coste de cambio futuro.

  • Si la relación es naturalmente de tipo (`es-un`) y estable, herencia puede ser válida.
  • Si esperas cambiar comportamientos frecuentemente, composición suele ser mejor.
  • Prefiere interfaces simples entre componentes para desacoplar capas.
  • Si una subclase empieza a desactivar lógica base, revisa diseño: probablemente necesitas composición.
Cambio de comportamiento por inyección
class MotorElectrico(Motor):
    def arrancar(self) -> str:
        return 'motor eléctrico encendido'


coche = Coche(MotorElectrico())
print(coche.iniciar())

🧪 Aprende probando

Ejemplo Ejemplo: servicio con estrategia inyectable Composición para cambiar cálculo de precio sin tocar la clase principal.

🏁 Retos

Reto Reto: introduce composición en `Coche` Añade dependencia `Motor` como atributo para delegar el arranque.

🧰 Recursos

Test

Comprueba tus conocimientos con un test sobre Python.

Test de Python

¿Qué es esto?

Soy Cristian Eslava y a veces hago webs para procrastinar yo y vosotros 😉.

Esta la hice en febrero de 2026 para facilitar el aprendizaje de mis alumnxs. Aprender desarrollo web practicando. La idea es que crezca semanalmente con nuevos temas, tests y retos.

Inspirado en MDN, en W3Schools, en Codepen, en el crack de Manz y en mil sitios de documentación sobre desarrollo web. Quería aportar además de bloques teóricos con ejemplos, la gamificación de los retos y el sistema de test que ya tenía en culTest .

Si te gustó, si no te gustó, si quieres saludarme, o invitarme a 🍻 no dudes en escribirme en cristianeslava@gmail.com .