As a (mainly) Python dev, I'm aware that there are DI frameworks out there, but personally I haven't to date used any of them.
My favourite little hack for simple framework-less DI in Python these days looks something like this:
# The code that we want to call
def do_foo(sleep_func = None):
_sleep_func = sleep_func if sleep_func is not None else time.sleep
for _ in range(10):
_sleep_func(1)
# Calling it in non-test code
# (we want it to actually take 10 seconds to run)
def main():
do_foo()
# Calling it in test code
# (we want it to take mere milliseconds to run, but nevertheless we
# want to test that it sleeps 10 times!)
def test_do_foo():
mock_sleep_func = MagicMock()
do_foo(sleep_func=mock_sleep_func)
assert mock_sleep_func.call_count == 10
However, in Python I prefer to use true DI. I mostly like Injector[0] because it’s lightweight and more like a set of primitives than an actual framework. Very easy to build functionality on top of and reuse - I have one set of modules that can be loaded for an API server, CLI, integration tests, offline workers, etc.
That said, I have a few problems with it - 2 features which I feel are bare minimum required, and one that isn’t there but could be powerful. You can’t provide async dependencies natively, which is not usable in 2025 - and it’s keyed purely on type, so if you want to return different string instances with some additional key you need a wrapper type.
Between these problems and missing features (Pydantic-like eval time validation of wiring graphs) I really want to write my own library.
However, as a testament to the flexibility of Injector, I could implement all 3 of these things as a layer on top without modifying its code directly.
Yeah, I use this sometimes too (even though Python makes "monkey patching" easy). However, note that it's simpler and clearer to use a default value for the argument:
def do_foo(sleep=time.sleep):
for _ in range(10):
sleep(1)
My favourite little hack for simple framework-less DI in Python these days looks something like this: