For Java, Dependency Injection works as pure OOP, i.e. you provide an interface to be implemented and in your framework code accept an instance of a class that implements the defined interface.
Now for Python, you are able to do the same way, but I think that method was too much overhead right in case of Python. So then how would you implement it in the Pythonic way?
Say this is the framework code:
class FrameworkClass(): def __init__(self, ...): ... def do_the_job(self, ...): # some stuff # depending on some external function
The most naive (and maybe the best?) way is to require the external function to be supplied into the FrameworkClass
constructor, and then be invoked from the do_the_job
method.
Framework Code:
class FrameworkClass(): def __init__(self, func): self.func = func def do_the_job(self, ...): # some stuff self.func(...)
Client Code:
def my_func(): # my implementation framework_instance = FrameworkClass(my_func) framework_instance.do_the_job(...)
The question is short. Is there any better commonly used Pythonic way to do this? Or maybe any libraries supporting such functionality?
Imagine I develop a micro web framework, which handles authentication using tokens. This framework needs a function to supply some ID
obtained from the token and get the user corresponding to that ID
.
Obviously, the framework does not know anything about users or any other application specific logic, so the client code must inject the user getter functionality into the framework to make the authentication work.
Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.
Types of Dependency Injection The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.
Python is an interpreted language with a dynamic typing. There is an opinion that dependency injection doesn't work for it as well as it does for Java. A lot of the flexibility is already built in. Also there is an opinion that a dependency injection framework is something that Python developer rarely needs.
See Raymond Hettinger - Super considered super! - PyCon 2015 for an argument about how to use super and multiple inheritance instead of DI. If you don't have time to watch the whole video, jump to minute 15 (but I'd recommend watching all of it).
Here is an example of how to apply what's described in this video to your example:
Framework Code:
class TokenInterface(): def getUserFromToken(self, token): raise NotImplementedError class FrameworkClass(TokenInterface): def do_the_job(self, ...): # some stuff self.user = super().getUserFromToken(...)
Client Code:
class SQLUserFromToken(TokenInterface): def getUserFromToken(self, token): # load the user from the database return user class ClientFrameworkClass(FrameworkClass, SQLUserFromToken): pass framework_instance = ClientFrameworkClass() framework_instance.do_the_job(...)
This will work because the Python MRO will guarantee that the getUserFromToken client method is called (if super() is used). The code will have to change if you're on Python 2.x.
One added benefit here is that this will raise an exception if the client does not provide a implementation.
Of course, this is not really dependency injection, it's multiple inheritance and mixins, but it is a Pythonic way to solve your problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With