Been messing about with python, as usual it throws my rigid static typed Object Oriented world in to a bit of a mess. Python supports duck typing, has no usable concept of interface based programming (as in C# interfaces) and allows Global variables. With all these goodies is there really any point to a dependency injection container or does the Python run-time become the container.
I understand the point to these containers in static typed OO languages such as Java and C# but where would such a thing fit into the nutty world of python (I love it)?
I have always suspected that Dependency injection as a design pattern was a bad smell that has been created by everything must be a class "Nazi thinking" that is c# and Java, would i be correct or is there something I am missing?
So far I think I can cover factories, Singletons, Multi-instance objects, just by using Globals. I also suspect that the Aspect stuff is covered too, although I am still thinking about this.
The Duck Typing is the thing that is getting me at the moment, so used to defining interfaces then basing classes on these interfaces and letting the static stuff cover my stupidity that I feel that without static typing, containers are a bit useless.
edit
I think I won't be using Dependency Injector frameworks/containers when using python. There really isn't any point. After thinking and reading the responses so far, the argument is made clear that without static type definitions the promises made are so loose that why bother at all. Duck typing is what it is, and the only promise can be made through documentation. As long as the reference comes into the class Method / function through a signiture parameter, and not coming through the ether of the programming environment, then I think I will be safe.
Alarming though is the fact that I can not enforce my will on others through my over bearing design practices as I have done in Java and C#. Do I care......nah :)
Dependency injection is a principle that helps to achieve an inversion of control. A dependency injection framework can significantly improve the flexibility of a language with static typing. Implementation of a dependency injection framework for a language with static typing is not something that one can do quickly.
The dependency injection technique enables you to improve this even further. It provides a way to separate the creation of an object from its usage. By doing that, you can replace a dependency without changing any code and it also reduces the boilerplate code in your business logic.
The IoC container that is also known as a DI Container is a framework for implementing automatic dependency injection very effectively. It manages the complete object creation and its lifetime, as well as it also injects the dependencies into the classes.
If you have a really small project with 12 classes, then a DI framework is almost certainly overkill. As a rule of thumb, the point where it becomes truly useful is when you find yourself repeatedly writing code that wires up object graphs with multiple dependencies and have to think about where to put that code.
has no usable concept of interface based programming (as in C# interfaces)
Just because the compiler can't check that you're using the interface correctly doesn't mean there's "no usable concept of interfaces". You document an interface, and write unit tests.
As for globals, it's not like public static
methods and fields on C# or Java classes are really any different. Consider how java.lang.Math works, for example. Now consider the fact that java.lang.Math isn't a Singleton. They did that for a good reason.
With all these goodies is there really any point to a dependency injection container
I doubt it, but then I never really saw the point of them in C# or Java, either. Dependency injection is a programming technique, in my view. And there's really not that much to it, either.
I have always suspected that Dependency injection as a design pattern was a bad smell that has been created by everything must be a class "Nazi thinking"
No, it isn't. Dependency injection is a good idea a lot of the time. You don't need a class to inject dependencies into, either. Every time you pass something to a free function as a parameter, instead of having the function call another function to get the information, you're basically doing the same thing: inversion of control. Python also lets you treat modules similarly to classes in a lot of ways (certainly more ways than Java and C# do). There are problems that can be solved by passing modules as parameters to functions. :)
So far I think I can cover factories, Singletons, Multi-instance objects, just by using Globals.
Singletons are the bad smell, if anything. In nearly every case, in my extensive experience, they exist because someone thought it would be Bad(TM) on principle to have a global, without really thinking through the possible options, or why they wanted that kind of access to a single shared object, or even why globals are "Bad(TM) on principle" in the first place.
You could make a global function in Python that acts as a factory. However, I would say it's more Pythonic to do any of the following:
a) first, make really, really, really sure you can't just do what you want with __init__
. I mean, in a dynamically typed language, you can do a heck of a lot that way.
b) If __init__
won't cut it, try using __new__
to control the behaviour.
In Python, classes are objects themselves, which are callable. By default, calling them instantiates the class. With __new__
, you can hook into that.
c) Use a decorator applied to the class. Here is an example that makes a Singleton (just because):
def _singleton(cls):
instance = cls()
result = lambda: instance
result.__doc__ = cls.__doc__
return result
@_singleton
class example(object): pass
The way this works: when you decorate the class, _singleton()
is called, with the class being passed in. An instance is constructed and cached, and _singleton()
returns an anonymous function that will return the instance when called. To complete the charade, the class's documentation is attached to the anonymous function. Then Python rebinds the class' name in the global scope to the returned anonymous function. So when you call it, you get the same instance of the class, every time.
Now, this can still be worked around, of course (you can do something like example().__class__()
to get another instance), but it's much more clear that you're doing something wrong than if you simply ignored a factory function in order to use the constructor normally. Plus, it means the calling code actually acts as if it were calling the constructor normally :)
The Duck Typing is the thing that is getting me at the moment, so used to defining interfaces then basing classes on these interfaces and letting the static stuff cover my stupidity that I feel that without static typing, containers are a bit useless.
You need to shift your thinking: stop worrying about what the thing you've been passed is, and worry about whether it can do what you want it to do. That's how duck typing works.
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