Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a Pythonic way for Dependency Injection?

Introduction

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?

Use Case

Say this is the framework code:

class FrameworkClass():     def __init__(self, ...):         ...      def do_the_job(self, ...):         # some stuff         # depending on some external function 

The Basic Approach

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(...) 

Question

The question is short. Is there any better commonly used Pythonic way to do this? Or maybe any libraries supporting such functionality?

UPDATE: Concrete Situation

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.

like image 599
bagrat Avatar asked Jul 28 '15 14:07

bagrat


People also ask

What is the right way to inject dependency?

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.

How many ways can you inject dependency?

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.

Why does Python not use dependency injection?

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.


1 Answers

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.

like image 136
Serban Teodorescu Avatar answered Sep 30 '22 21:09

Serban Teodorescu