Qu'est ce qu'un Pythonic façon pour l'Injection de Dépendances?
Introduction
Pour Java, l'Injection de Dépendance fonctionne comme pure de la POO, c'est à dire vous fournir une interface pour être mis en œuvre et dans votre code cadre accepter une instance d'une classe qui implémente l'interface définie.
Maintenant pour Python, vous êtes capable de faire la même façon, mais je pense que cette méthode a été trop frais généraux de droit dans le cas de Python. Alors comment voulez-vous mettre en œuvre dans le Pythonic façon?
Cas D'Utilisation
Dire que c'est le code de la structure:
class FrameworkClass():
def __init__(self, ...):
...
def do_the_job(self, ...):
# some stuff
# depending on some external function
L'Approche De Base
Le plus naïf (et peut-être le meilleur?) façon est d'exiger de la fonction externe pour être fourni dans la FrameworkClass
constructeur, et ensuite être appelée à partir de la do_the_job
méthode.
Code De La Structure:
class FrameworkClass():
def __init__(self, func):
self.func = func
def do_the_job(self, ...):
# some stuff
self.func(...)
Code Client:
def my_func():
# my implementation
framework_instance = FrameworkClass(my_func)
framework_instance.do_the_job(...)
Question
La question est de courte durée. Est-il mieux couramment utilisés Pythonic façon de le faire? Ou peut-être toutes les bibliothèques de l'appui d'une telle fonctionnalité?
Mise à JOUR: Situation Concrète
Imaginer que je développe un micro-framework web, qui gère l'authentification à l'aide de jetons. Ce cadre a besoin d'une fonction pour la fourniture de certains ID
obtenu à partir du jeton et obtenir de l'utilisateur correspondant à cette ID
.
Évidemment, le cadre ne sait rien sur les utilisateurs ou tout autre logique spécifique de l'application, de sorte que le code client doit injecter de l'utilisateur de lecture, des fonctionnalités dans le cadre de l'authentification de travail.
- Pourquoi ne pas vous "fournir une interface pour être mis en œuvre et dans votre code cadre accepter une instance d'une classe qui implémente l'interface définie"? En Python vous voulez faire cela dans un l'aeap style (c-à supposer qu'il répond à cette interface, et un
AttributeError
ouTypeError
obtient augmenté contraire), mais sinon, c'est la même chose. - Il est facile de le faire à l'aide
abs
'sABCMeta
métaclasse avec@abstractmethod
décorateur, et pas de manuel de validation. Veulent juste pour obtenir quelques options et suggestions. Celui que vous avez cité est la plus propre, mais je pense qu'avec plus de surcharge. - Alors je ne sais pas quelle question que vous essayez de le demander.
- Ok, je vais essayer en d'autres termes. Le problème est clair. La question est de savoir comment le faire dans Pythonic façon. Option 1: Le chemin que vous avez cité, Option 2: L'approche de base que j'ai décrit dans la question. La question est donc, tout les autres Pythonic les moyens de le faire?
- "Il devrait y avoir un, et de préférence seulement une façon évidente de le faire."
- Merci, je le sais 🙂 mais ici, il y a évidemment plus de l'une des manières.
- C'est évidemment très spécifique à l'application. Est-il une raison particulière pour laquelle, dans votre application, mafonction n'est pas enveloppé dans mysubclass? (Alors que vous n'avez pas besoin d'assigner dans
__init__
) - Merci pour le commentaire. J'ai mis à jour la question pour répondre à votre question.
- Ici vous pouvez trouver un bon exemple: code.activestate.com/recipes/413268
Vous devez vous connecter pour publier un commentaire.
Voir Raymond Hettinger - Super considéré super! - PyCon 2015 pour un argument sur la façon d'utiliser le super et l'héritage multiple à la place de DI. Si vous n'avez pas le temps de regarder la vidéo en entier, saut à 15 minutes (mais je vous conseille de regarder tout ça).
Voici un exemple de la façon d'appliquer à ce qui est décrit dans cette vidéo à votre exemple:
Code De La Structure:
Code Client:
Cela fonctionne parce que le Python MRO permettra de garantir que les getUserFromToken client méthode est appelée (si super() est utilisée). Le code devra changer si vous êtes sur Python 2.x.
Un avantage ici est que cela va lever une exception si le client ne fournit pas de mise en œuvre.
Bien sûr, ce n'est pas vraiment l'injection de dépendance, c'est l'héritage multiple et mixin, mais c'est un Pythonic façon de résoudre votre problème.
super()
🙂La façon de faire de l'injection de dépendances dans notre projet est à l'aide de la injecter lib. Découvrez la la documentation. Je vous recommande fortement de l'utiliser pour DI. Ça n'a aucun sens avec une seule fonction, mais commence à faire beaucoup de sens quand vous avez à gérer de multiples sources de données, etc, etc.
Suivant votre exemple, il pourrait être quelque chose de similaire à:
Votre fonction personnalisée:
Quelque part dans l'application que vous souhaitez créer un fichier d'amorçage, qui conserve la trace de toutes les dépendances définies:
Et puis vous pouvez consommer le code de cette façon:
J'ai peur c'est que pythonic qu'elle peut l'être (le module python douceur comme les décorateurs d'injecter par le paramètre etc - vérifier les docs), comme le python n'a pas de fantaisie comme les interfaces ou le type de l'affinage.
Donc à répondre à votre question directement serait très dur. Je pense que la vraie question est: est-python ont une certaine prise en charge native pour les DI? Et la réponse est malheureusement non.
Il y a quelques temps, j'ai écrit l'injection de dépendance microframework avec une ambition à faire Pythonic - La Dépendance De L'Injecteur. C'est ainsi que votre code peut ressembler dans le cas de son utilisation:
Voici un lien vers une description plus complète de cet exemple - http://python-dependency-injector.ets-labs.org/examples/services_miniapp.html
Espère que cela peut aider un peu. Pour plus d'informations, veuillez visiter:
Platform
etServices
). Est la solution pour créer un nouveau conteneur pour chaque combinaison de injectable bibliothèque de classes?Je pense que DI et, éventuellement, de l'AOP ne sont généralement pas considérés comme des Pythonic en raison de typique Python développeurs préférences, plutôt que les fonctionnalités du langage.
Comme une question de fait, vous pouvez mettre en œuvre une base DI cadre <100 lignes, à l'aide de metaclasses de classe et de décorateurs.
Pour une solution moins invasive, ces structures peuvent être utilisées pour plug-in des implémentations personnalisées dans un cadre générique.
En raison de Python de la programmation orientée objet la mise en œuvre du Cio et de l'injection de dépendance ne sont pas des pratiques courantes en Python monde. Néanmoins, l'approche semble prometteuse, même pour Python.
Donc mon solution est: