L’injection de dépendances en Python
Lucien Chemaly
31 octobre 2023
0 minutes de lectureL’injection de dépendances (DI) peut sembler complexe, mais elle vise simplement à rendre votre code plus flexible. Elle permet à vos logiciels de gagner en adaptabilité et en robustesse. Et comme Python est un langage de programmation très populaire, il est particulièrement utile de comprendre l’injection de dépendances. Imaginez des logiciels non seulement performants, mais excellents : faciles à ajuster, à étendre et à sécuriser. Voilà l’essence de l’injection de dépendances en Python.
Si vous cherchez comment intégrer l’injection de dépendances à votre travail, vous êtes au bon endroit. Ce tutoriel vous explique son fonctionnement, comment l’utiliser et comment elle peut améliorer vos projets Python.
Fonctionnement de l’injection de dépendances
Pour mieux comprendre le fonctionnement de l’injection de dépendances, imaginez l’assemblage d’une voiture. Il serait peu logique que chaque voiture doive fabriquer ses propres pneus, n’est-ce pas ? Dans une usine automobile, les pneus sont fabriqués séparément, puis montés sur la voiture. Ainsi, si une voiture a besoin d’autres pneus, il suffit de les remplacer. L’injection de dépendances repose sur le même principe, mais dans le domaine du logiciel.
Imaginez que vous exploriez une application Python. Elle contient une classe nommée DatabaseClient qui a besoin d’informations précises pour se connecter à une base de données. Si vous intégriez directement ces informations à la classe, ce serait comme une voiture dont on ne peut jamais changer les pneus. Avec l’injection de dépendances, au lieu de figer ces informations, vous les fournissez (ou les injectez) depuis l’extérieur. Ainsi, si vous souhaitez les modifier ou essayer une autre base de données par la suite, vous pouvez le faire sans remanier toute votre application.
Cette approche présente de nombreux avantages. C’est comme disposer d’une boîte à outils où vous pouvez facilement remplacer les outils en fonction du travail à effectuer. Votre logiciel gagne en flexibilité : vous pouvez expérimenter et tester facilement, ainsi qu’effectuer des mises à jour ou des corrections sans difficulté.
Découvrez maintenant quelques avantages de l’injection de dépendances pour mieux comprendre pourquoi vous en avez besoin.
Pourquoi utiliser l’injection de dépendances
L’injection de dépendances vous donne davantage de contrôle et vous simplifie la vie au quotidien. Découvrez quelques raisons clés d’envisager son intégration à vos projets.
Améliorer la maintenabilité et la testabilité du code
L’injection de dépendances est un modèle qui favorise le découplage des composants et réduit leur dépendance mutuelle. Ainsi, si un composant ou un service doit être mis à jour ou modifié, vous pouvez intervenir sans provoquer d’effet domino dans l’ensemble de la base de code.
Par ailleurs, l’injection de dépendances se prête particulièrement bien aux tests. Lorsque les composants sont découplés, il est beaucoup plus facile d’injecter des dépendances fictives lors des tests unitaires. Vous pouvez ainsi tester le comportement de chaque élément de manière isolée, pour des tests plus complets et plus robustes.
Remplacer facilement les dépendances
Avez-vous déjà dû relever le défi du changement de technologie, par exemple en passant d’une solution de base de données à une autre ? Avec l’injection de dépendances, ces transitions sont beaucoup moins difficiles. Plutôt que de remanier toute la classe ou le module qui interagit avec la base de données, il vous suffit de modifier la dépendance injectée. Cette flexibilité peut vous faire gagner un temps considérable et réduire le risque d’erreurs lors des migrations ou des mises à jour.
Renforcer la modularité et la réutilisabilité du code
L’injection de dépendances encourage la conception de composants qui ne sont pas étroitement liés à des implémentations spécifiques. Pour vous, cela se traduit par une base de code plus modulaire. Les modules ou composants conçus en tenant compte de l’injection de dépendances peuvent facilement être réutilisés dans différentes parties de votre application, voire dans des projets entièrement distincts. Vous pouvez ainsi accélérer le développement et favoriser une approche de programmation plus cohérente.
Prendre en charge l’inversion de contrôle
En programmation traditionnelle, les classes instancient et gèrent souvent leurs propres dépendances. Avec l’injection de dépendances, ce contrôle est inversé. Au lieu d’en confier la responsabilité à la classe, des entités externes (souvent un conteneur ou un framework d’injection de dépendances) se chargent de créer et de fournir ces dépendances. Cette inversion de contrôle (IoC) peut simplifier la gestion des dépendances et favoriser une architecture plus claire et mieux organisée.
Configurer facilement le comportement de l’application
L’un des avantages subtils, mais puissants, de l’injection de dépendances est la possibilité de modifier à la volée le comportement d’une application. En injectant différentes implémentations d’une dépendance, vous pouvez changer le fonctionnement de certaines parties de votre application sans réécrire de grandes quantités de code. Que vous souhaitiez vous adapter à différents environnements d’exécution ou répondre aux préférences de plusieurs utilisateurs, l’injection de dépendances vous offre la flexibilité nécessaire pour personnaliser le comportement de l’application.
Limites de l’injection de dépendances en Python
Bien que l’injection de dépendances offre de nombreux avantages, il est important de reconnaître qu’elle comporte aussi des difficultés et des limites. Tenez-en compte pour décider si vous souhaitez l’intégrer à vos projets Python :
Complexité : l’injection de dépendances modifie fondamentalement la manière dont les composants ou les objets sont instanciés et gérés dans une application. Dans une application tentaculaire et de grande envergure, sa mise en place exige de cartographier soigneusement les dépendances, les interfaces et les classes qui les implémentent. Cette couche supplémentaire peut entraîner davantage de code répétitif, de configuration et une courbe d’apprentissage plus abrupte, en particulier si vous adaptez un projet existant. Vous devez bien comprendre l’architecture de votre application pour réussir cette transition.
Risque de confusion : l’injection de dépendances peut être abstraite. Si vous ou vos collègues la découvrez ou la connaissez mal, certaines parties de la base de code risquent de vous sembler déroutantes. Au lieu d’instancier directement les objets, on vous les fournit ou les injecte, ce qui peut compliquer au début le suivi du flux d’exécution de l’application. L’intégration des nouveaux développeurs peut alors prendre plus de temps et la courbe d’apprentissage peut être plus abrupte.
Erreurs à l’exécution : les frameworks d’injection de dépendances établissent souvent les dépendances à l’exécution. En cas d’incompatibilité ou de configuration manquante, l’application risque de planter ou de se comporter de manière inattendue. Ces erreurs peuvent ne pas apparaître lors de la compilation ou des premiers tests, ce qui les rend plus difficiles à diagnostiquer et à corriger. Des tests adaptés et une bonne compréhension de l’injection de dépendances peuvent réduire ce risque, mais il reste à prendre en compte.
Surcoût en termes de performances : même s’il est souvent négligeable dans de nombreuses applications, le fait de résoudre et d’injecter des dépendances à l’exécution peut avoir un coût en performances. C’est particulièrement important lorsque chaque milliseconde compte, par exemple sur les plateformes de trading à haute fréquence. Il est essentiel de comparer les performances et de profiler votre application afin de comprendre ce surcoût et de l’optimiser au besoin.
Difficultés de retour en arrière : comme les dépendances sont étroitement liées dans l’injection de dépendances, il n’est pas toujours simple d’annuler une modification qui pose problème. Les dépendances peuvent avoir des effets en cascade : une modification dans une partie du système peut en toucher plusieurs autres. Des tests rigoureux, un contrôle de version et une documentation minutieuse sont donc d’autant plus essentiels.
Pas toujours nécessaire : l’injection de dépendances est particulièrement utile dans les applications complexes où les composants doivent être faiblement couplés, testés de manière isolée et plus modulaires. En revanche, pour un simple script ou une petite application avec peu de composants, l’intégrer peut être excessif. Vous risquez d’ajouter de la complexité sans en tirer de bénéfice concret. Comme pour tout modèle de conception ou choix d’architecture, il est essentiel d’évaluer sa pertinence au regard de la tâche à accomplir.
L’injection de dépendances dans les frameworks Python populaires
Dans cette section, vous découvrirez comment configurer l’injection de dépendances avec trois frameworks Python populaires : Flask, Django et FastAPI. Chaque framework adopte une approche qui lui est propre, mais tous reposent sur un même principe fondamental : le découplage des dépendances pour créer des applications plus faciles à maintenir, modulaires et testables.
Avant de découvrir ces frameworks, vérifiez que Python est installé. Si ce n’est pas le cas, vous pouvez le télécharger et l’installer depuis le site officiel de Python.
Maintenant que Python est installé sur votre machine, découvrez l’injection de dépendances dans ces différents frameworks.
L’injection de dépendances dans Flask
Flask est un framework web léger. Il ne prend pas en charge nativement l’injection de dépendances, mais vous pouvez intégrer des extensions comme Flask-Injector pour l’utiliser.
Pour installer Flask et Flask-Injector, utilisez la commande suivante :
Flask-Injector intègre de manière transparente la bibliothèque Injector pour gérer l’injection de dépendances dans les applications Flask.
Créer une application Flask
Pour créer une application Flask simple, créez un dossier nommé flask_di_project. Dans ce dossier, créez ensuite un fichier nommé app.py et ajoutez le code suivant :
Dans ce code, vous créez une application web Flask qui utilise l’injection de dépendances pour gérer ses composants. L’application se compose de trois classes : Database, Logger et DataService. Vous définissez les dépendances de la classe DataService par injection via le constructeur, ce qui vous permet d’injecter des instances de Database et de Logger lors de la création d’une instance de DataService. Grâce au décorateur @inject appliqué à la fonction de la route index, vous utilisez Flask-Injector pour injecter automatiquement une instance de DataService dans la fonction. De plus, une fonction configure définit la liaison de ces dépendances afin que Flask-Injector sache comment fournir chaque instance lorsqu’elle est requise.
Exécuter et tester l’application
Dans votre terminal ou shell, accédez au répertoire contenant app.py, puis exécutez la commande suivante :
Ouvrez un navigateur et accédez à http://127.0.0.1:5000/. Le message suivant devrait s’afficher : {"message": "Data from the Database!"} :

L’injection de dépendances dans Django
Django, un framework web de haut niveau, permet d’utiliser l’injection de dépendances grâce à des bibliothèques externes. Dans cet exemple, vous utilisez la bibliothèque Django Injector pour intégrer l’injection de dépendances à votre projet Django.
Utilisez la commande suivante pour installer Django et Django Injector :
Créer un projet et une application Django
Pour créer un projet et une application Django, utilisez les commandes suivantes :
Une fois django-injector installé, ajoutez-le à votre projet. Ouvrez le fichier settings.py situé dans le dossier django_di_project et ajoutez django_injector au tableau INSTALLED_APPS :
Ensuite, dans myapp/views.py, utilisez django-injector pour mettre en place l’injection de dépendances :
Vous avez ici défini une vue Django, MyView, qui, lorsqu’elle est appelée via une requête GET, récupère des données à l’aide de DataService, injecté comme dépendance, puis les renvoie au format JSON.
Mettre à jour les URL
Mettez à jour django_di_project/urls.py pour associer l’URL racine à cette vue :
Créez ensuite un fichier services.py dans le répertoire myapp et définissez-y la classe DataService :
En intégrant django-injector, vous avez ajouté de manière transparente l’injection de dépendances à votre application Django. Le décorateur @inject injecte efficacement l’instance de DataService dans le constructeur de la classe MyView, ce qui renforce la modularité et facilite la gestion de votre application Django.
Exécuter et tester l’application
Dans votre terminal ou shell, depuis le répertoire django_di_project, exécutez la commande suivante :
Ouvrez votre navigateur et accédez à http://127.0.0.1:8000/. Le message suivant devrait s’afficher : {"message": "Hello from Dynamic DataService in Django!"} :

L’injection de dépendances dans FastAPI
FastAPI est un framework web moderne qui prend nativement en charge l’injection de dépendances. En l’utilisant, vous profitez d’un framework qui intègre cette fonctionnalité et vous permet de créer des applications modulaires et testables sans dépendre de bibliothèques externes.
Utilisez le code suivant pour installer FastAPI et Uvicorn (un serveur ASGI permettant d’exécuter FastAPI) :
Créer une application FastAPI simple
Pour créer une application FastAPI simple, créez un nouveau dossier nommé fast_di_project dans votre répertoire racine. Dans ce dossier, créez un fichier nommé main.py et ajoutez le code suivant :
Commencez par créer une instance de la classe FastAPI. Définissez ensuite une classe DataService qui encapsule une méthode de récupération des données. Lorsque vous accédez à l’URL racine de votre application, le système de gestion des dépendances intégré à FastAPI entre en jeu. Vous avez créé une fonction get_data_service() qui fournit une instance de la classe DataService. Le mécanisme Depends de FastAPI vous permet d’injecter cette instance dans la fonction de route index. Lorsque vous visitez l’URL racine dans votre navigateur, vous recevez une réponse contenant les données récupérées, ainsi qu’un message personnalisé fourni par la classe dynamique DataService dans l’univers de FastAPI.
Exécuter et tester l’application
Dans votre terminal ou votre shell, accédez au répertoire contenant main.py, puis exécutez la commande suivante :
Ouvrez votre navigateur et rendez-vous sur http://127.0.0.1:8000/. Le message {"result":{"message":"Greetings from the Dynamic DataService in the World of FastAPI!"},"info":"Fetched from the Dynamic DataService in FastAPI!"} devrait s’afficher :

Tout le code utilisé dans ce tutoriel est disponible dans ce dépôt GitHub.
Frameworks d’injection de dépendances Python
Pour choisir un framework d’injection de dépendances, il est important d’évaluer les besoins spécifiques de votre projet, le niveau de modularité et de testabilité souhaité, ainsi que le framework que vous utilisez. Chaque option offre des fonctionnalités différentes. Votre choix doit correspondre à la complexité et aux objectifs de conception de votre projet. Découvrez quelques options :
Flask-Injector
Flask-Injector est un excellent choix pour créer des applications Flask. Il est particulièrement adapté aux projets légers reposant sur le framework Flask.
Flask-Injector s’intègre parfaitement à l’écosystème Flask, ce qui facilite la gestion des dépendances et la modularité de votre application Flask. Toutefois, pour les applications plus volumineuses et complexes qui nécessitent des fonctionnalités avancées de gestion des dépendances, vous pouvez envisager d’autres frameworks d’injection de dépendances offrant des fonctionnalités supplémentaires adaptées à ces besoins spécifiques.
Django Injector
Si vous développez avec Django, la bibliothèque Django Injector peut s’avérer très utile. Elle simplifie l’injection de dépendances dans les projets Django et constitue un excellent choix pour gagner en modularité et en testabilité.
Pensez à utiliser Django Injector pour créer des applications Django nécessitant une intégration transparente de l’injection de dépendances, notamment pour les vues basées sur des classes, les middlewares et les commandes de gestion.
Depends
La fonction Depends de FastAPI est conçue pour fonctionner avec le framework asyncio de Python et propose des fonctionnalités d’injection de dépendances pour le code asynchrone. Si vous développez des applications asynchrones avec FastAPI, Depends peut vous aider à gérer et à injecter des dépendances dans vos fonctions et coroutines asynchrones. Cette fonctionnalité est particulièrement utile pour les projets basés sur l’asynchrone avec FastAPI, lorsque vous souhaitez préserver la qualité du code et une conception modulaire.
Dependency Injector
La bibliothèque Dependency Injector est un framework complet d’injection de dépendances adapté à diverses applications Python. Elle propose des fonctionnalités avancées, comme la gestion des conteneurs et des portées, ainsi que le contrôle du cycle de vie.
Utilisez Dependency Injector pour les projets de grande envergure qui nécessitent une gestion robuste des dépendances, l’inversion de contrôle et la prise en charge de scénarios complexes vous offrant davantage de contrôle sur l’injection et la gestion des dépendances.
Injector
La bibliothèque Injector est un framework d’injection de dépendances généraliste qui s’intègre à différents projets Python, quel que soit le framework utilisé. Elle convient particulièrement aux projets pour lesquels vous souhaitez configurer et gérer manuellement l’injection de dépendances, sans intégration propre à un framework.
Utilisez Injector si vous avez besoin d’une solution d’injection de dépendances flexible et polyvalente pour des applications couvrant plusieurs frameworks, voire pour des scripts autonomes.
Sécurisez les dépendances de votre projet avec Snyk
Se concentrer sur les fonctionnalités ne vous permet pas de reléguer la sécurité au second plan. C’est là que Snyk peut vous aider. Avec la boîte à outils Snyk, vous pouvez :
Analyser les dépendances Python pour repérer les vulnérabilités et obtenir des suggestions de correction.
Recevoir des commentaires en temps réel sur les problèmes de sécurité pendant que vous codez.
Bénéficier de solutions automatisées pour les vulnérabilités détectées.
Intégrer facilement les pipelines d’intégration et de déploiement continus (CI/CD) les plus populaires afin de garantir des contrôles de sécurité systématiques.
En intégrant les extensions IDE Snyk à votre flux de travail, vous adoptez dès le départ des pratiques de codage sécurisé et simplifiez la gestion de vos dépendances. Pour en savoir plus sur Snyk, consultez la documentation officielle de Snyk.
Conclusion
Dans cet article, vous avez découvert pourquoi l’injection de dépendances est nécessaire en Python. Vous avez notamment appris certains de ses avantages, comme une meilleure maintenabilité et modularité du code. Vous avez également découvert les difficultés qu’elle peut entraîner, notamment une complexité accrue et des erreurs potentielles à l’exécution. Enfin, vous avez appris à intégrer l’injection de dépendances aux frameworks Python les plus connus, comme Flask, FastAPI et Django.
Bien que l’injection de dépendances puisse présenter certaines difficultés, en maîtriser les subtilités peut améliorer la qualité des applications Python. Lorsque vous gérez les dépendances, il est essentiel de vous appuyer sur des outils comme Snyk pour faire de la sécurité une priorité dans vos activités de développement. Pour approfondir la gestion des dépendances Python et découvrir les bonnes pratiques, consultez l’article du blog Snyk consacré au gestionnaire de paquets Python Poetry. Cette ressource présente en détail des outils qui peuvent vous aider à gérer vos projets Python plus efficacement.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis de capture du drapeau en regardant à la demande notre atelier virtuel d’initiation.
