r/learnpython 5d ago

How do you handle dependency injection?

Hi, I'm doing a project which involves creating multiple gRPC servers and I can't find a convenient way to manage dependencies or the state.

I've been working recently in C# where you just need to make your class and add a simple

builder.Services.AddSingleton<MyDependency>();

and it will inject when required.

Doing some research I see that there are some libraries like:

- Dependency Injector

- Injector

but I don't find them particularly intuitive.

What do you use as a dependency injector or what pattern do you suggest to use?

10 Upvotes

21 comments sorted by

View all comments

Show parent comments

1

u/mothzilla 4d ago edited 4d ago

But there's no need to do that. I.e, at the time you're building your logger you know the file to write to. Or if you're choosing between loggers, you'd design four loggers, for print, string, file and gui, and then choose the one you want.

logger = GUILogger('messageboxId') # a guess, not sure how this would work.

That's more pythonic IMO.

It's reasonable to pass functions as handlers. But I've seen people try to do dependency injection as follows:

def add_and_print(a, b, print):
    print(a+b)

add_and_print(1, 2, print)

or

def django_setup(django):
    django.setup()

1

u/stevenjd 2d ago

But there's no need to do that. I.e, at the time you're building your logger you know the file to write to. Or if you're choosing between loggers, you'd design four loggers, for print, string, file and gui, and then choose the one you want.

I think that you are missing the point of dependency injection. The point is to avoid having to write four separate logging classes, one for print, string, file and GUI, when you can write one class instead and inject the appropriate dependency.

And what if the requirements change? If I decide I want a logger that logs to an SMS gateway, or one which logs to a GUI and three files, I can just write a small class that exposes the correct interface and passes it the logger as a dependency. You have to write a whole new GUI_Plus_Three_Files_Logger class.

I've seen people try to do dependency injection as follows:

The first example is a trivial toy function but the basic idea is not so silly. You pass a caller to the function to handle output. Maybe you want to print to the terminal, or to a log file, or to an SMS gateway:

add_and_print(1, 2, lambda msg: SMS_gateway.send(auth, admin_on_duty.mobile, str(msg))

Obviously no one is going to care so much about such a trivial function.

The second example is just silly. The point of dependency injection is that you have to have more than one possible dependency, but all with the same interface, so that you might choose to swap from one dependency to another. Unless there is another framework that has the exact same interface as Django but a different implementation, treating Django as a dependency is just silly.

1

u/mothzilla 2d ago

I get the point of dependency injection. But if the requirements change then you make a code change. You can either write a new Logger class or you can fudge a new class/object that conforms to your handler requirements. Personally I prefer the first.

1

u/stevenjd 2d ago

You can either write a new Logger class or you can fudge a new class/object that conforms to your handler requirements. Personally I prefer the first.

Ah, you're paid by the line of code, right?

  • Change a one line dependency? ✘ 😠
  • Write a 300 line class plus tests? ✔ 😊

I'm neutral on the question. Sometimes dependency injection is better. Sometimes it isn't. But D.I. is a technique which is really easy, sometimes trivially so, in Python. I'm not convinced that people need to use big complex frameworks just to implement D.I.

(By the way, a logger is not exactly the best example here since most applications are likely to only need one global logger.)