design patterns – Why is IoC / DI not common in Python?

design patterns – Why is IoC / DI not common in Python?

I dont actually think that DI/IoC are that uncommon in Python. What is uncommon, however, are DI/IoC frameworks/containers.

Think about it: what does a DI container do? It allows you to

  1. wire together independent components into a complete application …
  2. … at runtime.

We have names for wiring together and at runtime:

  1. scripting
  2. dynamic

So, a DI container is nothing but an interpreter for a dynamic scripting language. Actually, let me rephrase that: a typical Java/.NET DI container is nothing but a crappy interpreter for a really bad dynamic scripting language with butt-ugly, sometimes XML-based, syntax.

When you program in Python, why would you want to use an ugly, bad scripting language when you have a beautiful, brilliant scripting language at your disposal? Actually, thats a more general question: when you program in pretty much any language, why would you want to use an ugly, bad scripting language when you have Jython and IronPython at your disposal?

So, to recap: the practice of DI/IoC is just as important in Python as it is in Java, for exactly the same reasons. The implementation of DI/IoC however, is built into the language and often so lightweight that it completely vanishes.

(Heres a brief aside for an analogy: in assembly, a subroutine call is a pretty major deal – you have to save your local variables and registers to memory, save your return address somewhere, change the instruction pointer to the subroutine you are calling, arrange for it to somehow jump back into your subroutine when it is finished, put the arguments somewhere where the callee can find them, and so on. IOW: in assembly, subroutine call is a Design Pattern, and before there were languages like Fortran which had subroutine calls built in, people were building their own subroutine frameworks. Would you say that subroutine calls are uncommon in Python, just because you dont use subroutine frameworks?)

BTW: for an example of what it looks like to take DI to its logical conclusion, take a look at Gilad Brachas Newspeak Programming Language and his writings on the subject:

IoC and DI are super common in mature Python code. You just dont need a framework to implement DI thanks to duck typing.

The best example is how you set up a Django application using settings.py:

# settings.py
CACHES = {
    default: {
        BACKEND: django_redis.cache.RedisCache,
        LOCATION: REDIS_URL + /1,
    },
    local: {
        BACKEND: django.core.cache.backends.locmem.LocMemCache,
        LOCATION: snowflake,
    }
}

Django Rest Framework utilizes DI heavily:

class FooView(APIView):
    # The injected dependencies:
    permission_classes = (IsAuthenticated, )
    throttle_classes = (ScopedRateThrottle, )
    parser_classes = (parsers.FormParser, parsers.JSONParser, parsers.MultiPartParser)
    renderer_classes = (renderers.JSONRenderer,)

    def get(self, request, *args, **kwargs):
        pass

    def post(self, request, *args, **kwargs):
        pass

Let me remind (source):

Dependency Injection is a 25-dollar term for a 5-cent concept. […] Dependency injection means giving an object its instance variables. […].

design patterns – Why is IoC / DI not common in Python?

Part of it is the way the module system works in Python. You can get a sort of singleton for free, just by importing it from a module. Define an actual instance of an object in a module, and then any client code can import it and actually get a working, fully constructed / populated object.

This is in contrast to Java, where you dont import actual instances of objects. This means you are always having to instantiate them yourself, (or use some sort of IoC/DI style approach). You can mitigate the hassle of having to instantiate everything yourself by having static factory methods (or actual factory classes), but then you still incur the resource overhead of actually creating new ones each time.

Leave a Reply

Your email address will not be published.