What is a Pythonic way for Dependency Injection? What is a Pythonic way for Dependency Injection? python python

What is a Pythonic way for Dependency Injection?


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 NotImplementedErrorclass 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 userclass ClientFrameworkClass(FrameworkClass, SQLUserFromToken):    passframework_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.


The way we do dependency injection in our project is by using the inject lib. Check out the documentation. I highly recommend using it for DI. It kinda makes no sense with just one function but starts making lots of sense when you have to manage multiple data sources etc, etc.

Following your example it could be something similar to:

# framework.pyclass FrameworkClass():    def __init__(self, func):        self.func = func    def do_the_job(self):        # some stuff        self.func()

Your custom function:

# my_stuff.pydef my_func():    print('aww yiss')

Somewhere in the application you want to create a bootstrap file that keeps track of all the defined dependencies:

# bootstrap.pyimport injectfrom .my_stuff import my_funcdef configure_injection(binder):    binder.bind(FrameworkClass, FrameworkClass(my_func))inject.configure(configure_injection)

And then you could consume the code this way:

# some_module.py (has to be loaded with bootstrap.py already loaded somewhere in your app)import injectfrom .framework import FrameworkClassframework_instance = inject.instance(FrameworkClass)framework_instance.do_the_job()

I'm afraid this is as pythonic as it can get (the module has some python sweetness like decorators to inject by parameter etc - check the docs), as python does not have fancy stuff like interfaces or type hinting.

So to answer your question directly would be very hard. I think the true question is: does python have some native support for DI? And the answer is, sadly: no.


Some time ago I wrote dependency injection microframework with a ambition to make it Pythonic - Dependency Injector. That's how your code can look like in case of its usage:

"""Example of dependency injection in Python."""import loggingimport sqlite3import boto.s3.connectionimport example.mainimport example.servicesimport dependency_injector.containers as containersimport dependency_injector.providers as providersclass Platform(containers.DeclarativeContainer):    """IoC container of platform service providers."""    logger = providers.Singleton(logging.Logger, name='example')    database = providers.Singleton(sqlite3.connect, ':memory:')    s3 = providers.Singleton(boto.s3.connection.S3Connection,                             aws_access_key_id='KEY',                             aws_secret_access_key='SECRET')class Services(containers.DeclarativeContainer):    """IoC container of business service providers."""    users = providers.Factory(example.services.UsersService,                              logger=Platform.logger,                              db=Platform.database)    auth = providers.Factory(example.services.AuthService,                             logger=Platform.logger,                             db=Platform.database,                             token_ttl=3600)    photos = providers.Factory(example.services.PhotosService,                               logger=Platform.logger,                               db=Platform.database,                               s3=Platform.s3)class Application(containers.DeclarativeContainer):    """IoC container of application component providers."""    main = providers.Callable(example.main.main,                              users_service=Services.users,                              auth_service=Services.auth,                              photos_service=Services.photos)

Here is a link to more extensive description of this example - http://python-dependency-injector.ets-labs.org/examples/services_miniapp.html

Hope it can help a bit. For more information please visit: