Inyección de dependencias en Python
Lucien Chemaly
31 de octubre de 2023
0 minutos de lecturaLa inyección de dependencias (DI) puede sonar compleja, pero en realidad se trata de mejorar la flexibilidad de tu código. Es como darle a tu software un impulso para que sea más adaptable y sólido. Y como Python es un lenguaje de programación muy popular, entender la inyección de dependencias es especialmente valioso. Imagina crear software que no solo sea bueno, sino excelente: fácil de ajustar, ampliar y proteger. Esa es la esencia de la DI en Python.
Si buscas cómo agregar la inyección de dependencias a tu trabajo, llegaste al lugar indicado. En este tutorial aprenderás cómo funciona la DI, cómo usarla y cómo puede mejorar tus proyectos de Python.
Cómo funciona la inyección de dependencias
Para entender mejor cómo funciona la DI, piensa en cómo se ensambla un auto. No tendría mucho sentido que cada auto tuviera que fabricar sus propias llantas, ¿verdad? En una fábrica de autos, las llantas se fabrican por separado y luego se instalan en el auto. Así, si un auto necesita otras llantas, se pueden cambiar. La DI aplica esta misma idea al mundo del software.
Imagina que estás explorando una aplicación de Python. Dentro hay una clase llamada DatabaseClient que necesita información específica para conectarse a una base de datos. Si incluyeras esta información directamente en la clase, sería como tener un auto con llantas que no se pueden cambiar. Pero con la DI, en lugar de dejar fija esa información, la proporcionas (o inyectas) desde el exterior. Así, si más adelante quieres cambiar los datos o probar otra base de datos, puedes hacerlo sin desarmar toda la aplicación.
Este enfoque ofrece muchos beneficios. Es como tener una caja de herramientas en la que puedes cambiar fácilmente las herramientas según el trabajo. Tu software se vuelve más flexible; puedes experimentar y hacer pruebas con facilidad, además de implementar actualizaciones o correcciones.
A continuación, revisa algunos beneficios de la inyección de dependencias para entender mejor por qué la necesitas.
Por qué necesitas la inyección de dependencias
La DI te da más control y facilita tu trabajo de programación. Descubre algunas razones clave para considerar incorporarla en tus proyectos.
Mejora la mantenibilidad y la capacidad de prueba del código
La inyección de dependencias es un patrón que promueve el desacoplamiento de los componentes y hace que dependan menos unos de otros. Esto significa que, si necesitas actualizar o modificar un componente o servicio en particular, puedes hacerlo sin causar un efecto dominó en toda la base de código.
Además, la DI es ideal para las pruebas. Cuando los componentes están desacoplados, es mucho más fácil inyectar dependencias simuladas durante las pruebas unitarias. Así puedes probar el comportamiento de partes individuales de forma aislada y realizar pruebas más completas y sólidas.
Permite cambiar las dependencias fácilmente
¿Alguna vez te enfrentaste a la difícil tarea de cambiar de tecnología, como migrar de una solución de base de datos a otra? Con la DI, estas transiciones son mucho más sencillas. En lugar de modificar toda la clase o el módulo que interactúa con la base de datos, solo tienes que cambiar la dependencia inyectada. Esta flexibilidad puede ahorrarte mucho tiempo y reducir la posibilidad de errores durante las migraciones o actualizaciones.
Mejora la modularidad y la reutilización del código
La inyección de dependencias fomenta el diseño de componentes que no están estrictamente vinculados a implementaciones específicas. Para ti, esto se traduce en una mayor modularidad de la base de código. Los módulos o componentes diseñados con la DI en mente se pueden reutilizar fácilmente en distintas partes de tu aplicación o incluso en proyectos completamente independientes. Esto puede acelerar el desarrollo y fomentar un enfoque de programación más uniforme.
Admite la inversión de control
En la programación tradicional, las clases suelen crear y administrar sus propias dependencias. Con la DI, este control se invierte. En lugar de que la clase sea responsable, entidades externas (a menudo un contenedor o framework de DI) se encargan de crear y proporcionar estas dependencias. Esta inversión de control (IoC) puede simplificar la administración de dependencias y promover una arquitectura más limpia y organizada.
Facilita la configuración del comportamiento de la aplicación
Una de las ventajas sutiles, pero poderosas, de la DI es su capacidad para cambiar el comportamiento de la aplicación sobre la marcha. Al inyectar distintas implementaciones de una dependencia, puedes modificar el funcionamiento de ciertas partes de la aplicación sin reescribir grandes cantidades de código. Ya sea que te adaptes a distintos entornos de ejecución o respondas a las preferencias de varios usuarios, la DI te da la flexibilidad para adaptar el comportamiento de la aplicación.
Limitaciones de la inyección de dependencias en Python
Aunque la DI ofrece muchos beneficios, es importante reconocer que también presenta desafíos y limitaciones. Ten en cuenta estas limitaciones al decidir si quieres incorporarla en tus proyectos de Python:
Complejidad: La DI cambia de manera fundamental cómo se crean y administran los componentes u objetos de una aplicación. En una aplicación extensa y de gran escala, configurar la DI requiere asignar cuidadosamente las dependencias, las interfaces y las clases que las implementan. Esta capa adicional puede implicar más código repetitivo, más configuración y una curva de aprendizaje más pronunciada, sobre todo si estás adaptando un proyecto existente para usar DI. Para hacerlo correctamente, necesitas comprender a fondo la arquitectura de tu aplicación.
Posible confusión: La DI puede ser abstracta. Si tú o tus compañeros de equipo no conocen bien la DI, es posible que algunas partes de la base de código les resulten confusas. En lugar de crear los objetos directamente, estos se proporcionan o inyectan, lo que al principio puede dificultar el seguimiento del flujo de una aplicación. Esto puede prolongar la incorporación de nuevos desarrolladores o aumentar la curva de aprendizaje.
Errores en tiempo de ejecución: Los frameworks de DI suelen conectar las dependencias en tiempo de ejecución. Si hay una incompatibilidad o falta una configuración, la aplicación puede fallar o comportarse de forma inesperada. Estos errores podrían no detectarse durante la compilación o las pruebas iniciales, por lo que puede ser más difícil diagnosticarlos y corregirlos. Las pruebas adecuadas y el conocimiento de la DI pueden ayudar a evitarlo, pero sigue siendo un riesgo potencial.
Sobrecarga de rendimiento: Aunque en muchas aplicaciones esta sobrecarga suele ser insignificante, resolver e inyectar dependencias en tiempo de ejecución puede afectar el rendimiento. Esto es especialmente relevante en situaciones en las que cada milisegundo cuenta, como las plataformas de trading de alta frecuencia. Es fundamental evaluar y medir el rendimiento de tu aplicación para comprender esta sobrecarga y optimizarla cuando sea necesario.
Dificultades para revertir cambios: Como las dependencias de la DI están estrechamente vinculadas, no siempre es sencillo revertir un cambio que causa problemas. Las dependencias pueden generar efectos en cadena, lo que significa que un cambio en un área puede afectar a muchos otros componentes. Por eso, las pruebas exhaustivas, el control de versiones y la documentación detallada son aún más importantes.
No siempre es necesaria: La DI resulta muy útil en aplicaciones complejas cuyos componentes deben tener un acoplamiento débil y probarse de forma aislada, y en las que se necesita una mayor modularidad. Sin embargo, en un script simple o una aplicación pequeña con pocos componentes, incorporar DI podría ser excesivo. Podría agregar complejidad sin aportar beneficios concretos. Como ocurre con cualquier patrón de diseño o decisión arquitectónica, es importante evaluar si es adecuado para la tarea.
Inyección de dependencias en frameworks populares de Python
En esta sección aprenderás a configurar la inyección de dependencias con tres frameworks populares de Python: Flask, Django y FastAPI. Aunque cada framework tiene su propio enfoque, todos comparten un principio fundamental: desacoplar las dependencias para crear aplicaciones más fáciles de mantener, modulares y sencillas de probar.
Antes de explorar los frameworks, asegúrate de tener Python instalado. Si aún no lo tienes, puedes descargarlo e instalarlo desde el sitio web oficial de Python.
Ahora que tienes Python en tu equipo, explora la inyección de dependencias en estos distintos frameworks.
Inyección de dependencias en Flask
Flask es un framework web ligero. Aunque no ofrece compatibilidad integrada con la DI, puedes integrar extensiones como Flask-Injector para implementarla.
Para instalar Flask y Flask-Injector, usa el siguiente comando:
Flask-Injector integra sin problemas la biblioteca Injector para controlar la inyección de dependencias en aplicaciones de Flask.
Crea una aplicación de Flask
Para crear una aplicación simple de Flask, crea una carpeta llamada flask_di_project. Luego, dentro de esta carpeta, crea un archivo nuevo llamado app.py y agrega el siguiente código:
En este código, creas una aplicación web de Flask que utiliza la inyección de dependencias para administrar sus componentes. La aplicación consta de tres clases: Database, Logger y DataService. Defines las dependencias de la clase DataService mediante la inyección por constructor, lo que te permite inyectar instancias de Database y Logger al crear una instancia de DataService. Con el decorador @inject en la función de ruta index, usas Flask-Injector para inyectar automáticamente una instancia de DataService en la función. Además, una función configure define la asociación de estas dependencias para que Flask-Injector sepa cómo proporcionarlas cuando se necesite una instancia.
Ejecuta y prueba la aplicación
En la terminal o shell, ve al directorio que contiene app.py y ejecuta lo siguiente:
Abre un navegador y ve a http://127.0.0.1:5000/. Deberías ver el mensaje {"message": "Data from the Database!"}:

Inyección de dependencias en Django
Django, un framework web de alto nivel, ofrece opciones para usar DI mediante bibliotecas externas. En este caso, usarás la biblioteca Django Injector para incorporar la DI a tu proyecto de Django.
Usa el siguiente comando para instalar Django y Django Injector:
Crea un nuevo proyecto y una aplicación de Django
Para crear un nuevo proyecto y una aplicación de Django, usa los siguientes comandos:
Una vez que hayas instalado django-injector, debes agregarlo a tu proyecto. Ve al archivo settings.py, ubicado dentro de la carpeta django_di_project, y agrega django_injector al arreglo INSTALLED_APPS:
Luego, en myapp/views.py, usa django-injector para implementar la DI:
Aquí defines una vista de Django, MyView, que, cuando recibe una solicitud GET, obtiene datos mediante DataService, cuya dependencia se inyecta, y los devuelve como respuesta JSON.
Actualiza las URL
Actualiza django_di_project/urls.py para dirigir la URL raíz a esta vista:
Luego, crea un archivo services.py en el directorio myapp y define allí la clase DataService:
Al incorporar django-injector, integraste sin problemas la DI en tu aplicación de Django. El decorador @inject inyecta de forma eficiente la instancia de DataService en el constructor de la clase MyView, lo que promueve la modularidad y facilita la administración de tu aplicación de Django.
Ejecuta y prueba la aplicación
En la terminal o shell, dentro del directorio django_di_project, ejecuta lo siguiente:
Abre el navegador y ve a http://127.0.0.1:8000/. Deberías ver el mensaje {"message": "Hello from Dynamic DataService in Django!"}:

Inyección de dependencias en FastAPI
FastAPI es un framework web moderno que incluye compatibilidad nativa con la DI. Al usar FastAPI, eliges un framework que integra la DI de forma nativa, lo que te permite crear aplicaciones modulares y fáciles de probar sin depender de bibliotecas externas.
Usa el siguiente código para instalar FastAPI y Uvicorn (un servidor ASGI para ejecutar FastAPI):
Crea una aplicación sencilla de FastAPI
Para crear una aplicación sencilla con FastAPI, crea una carpeta nueva llamada fast_di_project en el directorio raíz. Dentro de esta carpeta, crea un archivo llamado main.py y agrega el siguiente código:
Aquí, empiezas por crear una instancia de la clase FastAPI. Luego, defines una clase DataService que encapsula un método para obtener datos. Cuando accedes a la URL raíz de tu aplicación, entra en acción la administración de dependencias integrada de FastAPI. Creaste una función get_data_service() para proporcionar una instancia de la clase DataService. El mecanismo Depends de FastAPI te permite inyectar esta instancia en la función de ruta index. Cuando visitas la URL raíz en tu navegador, recibes una respuesta que contiene los datos obtenidos junto con un mensaje personalizado de DataService, que es dinámico y forma parte del universo de FastAPI.
Ejecuta y prueba la aplicación
En tu terminal o shell, navega hasta el directorio que contiene main.py y ejecuta lo siguiente:
Abre el navegador y ve a http://127.0.0.1:8000/. Deberías ver el mensaje {"result":{"message":"Greetings from the Dynamic DataService in the World of FastAPI!"},"info":"Fetched from the Dynamic DataService in FastAPI!"}:

Todo el código que se usa en este tutorial está disponible en este repositorio de GitHub.
Frameworks de inyección de dependencias para Python
Al decidir qué framework de DI usar, es importante evaluar los requisitos específicos de tu proyecto, el nivel de modularidad y facilidad de prueba que buscas, y el framework con el que trabajas. Cada opción ofrece distintas capacidades, y tu elección debe ajustarse a la complejidad y los objetivos de diseño de tu proyecto. Estas son algunas opciones:
Flask-Injector
Flask-Injector es una excelente opción para crear aplicaciones con Flask. Es especialmente útil para proyectos ligeros basados en este framework.
Flask-Injector se integra a la perfección con el ecosistema de Flask, lo que facilita administrar dependencias y lograr modularidad en tu aplicación Flask. Sin embargo, para aplicaciones más grandes y complejas que podrían requerir funciones más avanzadas de administración de dependencias, puedes explorar otros frameworks de DI con capacidades adicionales adaptadas a esas necesidades específicas.
Django Injector
Si desarrollas con Django, la biblioteca Django Injector puede ser un recurso valioso. Simplifica la DI en los proyectos de Django, por lo que es una excelente opción para lograr modularidad y facilidad de prueba.
Considera usar Django Injector para crear aplicaciones con Django que requieran una integración fluida de DI, especialmente en vistas basadas en clases, middleware y comandos de administración.
Depends
La función Depends de FastAPI está diseñada para funcionar con el framework asyncio de Python y ofrece funciones de DI para código asíncrono. Si creas aplicaciones asíncronas con FastAPI, Depends puede ayudarte a administrar e inyectar dependencias en tus funciones asíncronas y corrutinas. Esta función es especialmente valiosa al trabajar en proyectos basados en async con FastAPI, ya que ayuda a mantener la calidad del código y un diseño modular.
Dependency Injector
La biblioteca Dependency Injector es un framework de DI completo, apto para diversas aplicaciones de Python. Ofrece funciones avanzadas, como administración de contenedores, ámbitos y control del ciclo de vida.
Usa Dependency Injector en proyectos más grandes que requieran una administración sólida de dependencias, inversión de control y escenarios complejos en los que necesites más control sobre la forma de inyectar y administrar las dependencias.
Injector
La biblioteca Injector es un framework de DI de propósito general que se puede integrar en distintos proyectos de Python, sin importar el framework. Es especialmente adecuada para proyectos en los que quieres configurar y administrar manualmente la inyección de dependencias, sin integraciones específicas para cada framework.
Usa Injector cuando necesites una solución de DI flexible y versátil para aplicaciones que abarquen varios frameworks o incluso para scripts independientes.
Protege las dependencias de tu proyecto con Snyk
Al enfocarte en la funcionalidad, no puedes dejar la seguridad de lado. Aquí es donde Snyk puede ayudarte. Con el conjunto de herramientas de Snyk, puedes hacer lo siguiente:
Analizar las dependencias de Python para detectar vulnerabilidades y recibir sugerencias para corregirlas.
Recibir comentarios en tiempo real sobre problemas de seguridad mientras programas.
Aprovechar soluciones automatizadas para las vulnerabilidades detectadas.
Integrarte fácilmente con los pipelines de integración y entrega continuas (CI/CD) más populares para garantizar comprobaciones de seguridad constantes.
Al incorporar las extensiones de Snyk para IDE en tu flujo de trabajo, adoptas prácticas de programación segura de forma proactiva desde el principio y simplificas el proceso de administración de dependencias. Para obtener más información sobre Snyk, consulta la documentación oficial de Snyk.
Conclusión
En este artículo, aprendiste por qué necesitas la inyección de dependencias en Python. También conociste algunos de sus beneficios, como una mejor mantenibilidad y modularidad del código. Además, aprendiste sobre algunos de los desafíos que presenta, entre ellos la posibilidad de una mayor complejidad y de errores en tiempo de ejecución. También aprendiste a integrar la inyección de dependencias en frameworks de Python ampliamente reconocidos, como Flask, FastAPI y Django.
Aunque la DI puede presentar ciertos desafíos, dominar sus particularidades puede elevar la calidad de tus aplicaciones de Python. A medida que exploras la administración de dependencias, es fundamental aprovechar herramientas como Snyk para mantener la seguridad como prioridad en tus proyectos de desarrollo. Para conocer más sobre la administración de dependencias en Python y las prácticas recomendadas, te recomendamos explorar el administrador de paquetes Python Poetry en el blog de Snyk. Este recurso ofrece una descripción completa de las herramientas que pueden ayudarte a administrar tus proyectos de Python de forma más eficiente.
Empieza con los desafíos de Capture the Flag
Aprende a resolver desafíos de captura la bandera con nuestro taller virtual introductorio a pedido.
