3 ms·
> The “problem” people try to > solve with things like > dependency injection isn’t > even a problem in python. > 99.99% of the time you can
by indigo945 2y ago
> The “problem” people try to
> solve with things like
> dependency injection isn’t
> even a problem in python.
> 99.99% of the time you can
> just import you dependencies
> everywhere they are needed.
That's... Just not the problem DI fixes in any language? Sure, in C++ or Java you can just create a global static instance and use that everywhere. That's pretty much equivalent to just importing the same thing everywhere. But the downside of both approaches is testability: it becomes much harder to test units in isolation when they access global resources.
Consider a function with `import datetime`, that gets the current time and does something with it. You want to make sure that this function still does the right thing in the extreme case of the current time being 23:59:59. How do you write this test without DI?
- wizzwizz4 2y agoEasily. from datetime import datetime, timedelta def f(): now = datetime.now() future = now + timedelta(seconds=1) return now.time() < future.time() from unittest.mock import patch with patch('__main__.datetime', spec=datetime, side_effect=datetime) as mockdt: mockdt.now.return_value = datetime(2024, 10, 3, 23, 59, 59) assert f() If `datetime.datetime` were implemented in pure Python, one could even use `patch.object` here, saving a line.
- Hackbraten 2y agoI feel reluctant about mocking types I don’t own, and prefer small, tailored abstractions instead: from datetime import datetime, timedelta def f(now = datetime.now): timestamp = now() future = timestamp + timedelta(seconds=1) return timestamp.time() < future.time() def mockdt(): return datetime(2024, 10, 3, 23, 59, 59) assert f(mockdt) Admittedly, this approach adds _some_ noise to the function signature. On the other hand, it feels more honest. It makes it unmistakably clear that this API relies on, and uses, some external state. Also, this approach scales poorly with the number of dependencies, and that’s a good thing. If `f` were to also depend on a `db_connection` in addition to `datetime.now`, then this pattern automatically alerts the API designer that it might be time to redesign `f`.
- indigo945 2y agoExactly! And now you've invented Dependency Injection. That's all DI means, passing dependencies to where they're needed instead of pulling them in via global state. You're doing it by hand (and in an impure way) instead of relying on an IoC container for convenience, but it's still the same thing.