Wat is dependency injection?
In software engineering, dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services. Instead, the receiving “client” (object or function) is provided with its dependencies by external code (an “injector”), which it is not aware of. Dependency injection makes implicit dependencies explicit and helps solve the following problems:
- How can a class be independent from the creation of the objects it depends on?
- How can an application and the objects it uses support different configurations?
Dependency injection is often used to keep code in-line with the dependency inversion principle.
Hier een duidelijke video:
Dependency Injection frameworks voor Python
Mocht je dependency injection gebruiken heb je een ruime keuze aan frameworks. Lees goed de documentatie door om te kijken welke het beste aansluit bij jouw ontwerp en/of project.
Framework | - |
---|---|
Dependency Injector | Dependency injection framework for Python. |
Injector | Python dependency injection framework, inspired by Guice. |
Dishka | Cute DI framework with agreeable API and everything you need. |
Inject | Python dependency injection. |
Kink | Dependency injection container made for Python. |
di | Pythonic dependency injection. |
lagom | Type based auto-wiring dependency injection with support for async and threading. |
That Depends | simple DI-framework, inspired by python-dependency-injector, but without wiring |
Het gebruik van lagom
Waarom lagom?
Ik heb gekozen voor het framework ‘lagom’ omdat het simpel en minimalistisch is. Ik ben meerdere dependency injection frameworks afgegaan en merkte de volgende problemen op bij de meeste libraries:
- De syntax is verbose.
- Het registreren van dependencies werkt niet met abstracte klassen en/of interfaces.
- De documentatie is incompleet.
- Er moet handmatig met annotaties gespecificeerd worden hoe de injectie plaatsvindt.
- Er is geen
async
support.
Een minimaal voorbeeld
Als je een singleton wilt gebruiken kan je het direct initiëren:
container[SomeClassToLoadOnce] = SomeClassToLoadOnce("up", "left")
Of pas initiëren wanneer het nodig is met:
container[SomeClassToLoadOnce] = Singleton(SomeClassToLoadOnce)
Dus als je alleen singletons hebt en alles in je DI container stopt kan je zo je applicatie opzetten:
class DIContainer:
@staticmethod
def build_container() -> Container:
"""Builds the container containing the dependencies. This is our DI method."""
container = Container()
container[IConfigHandler] = Singleton(ConfigHandler)
container[IKivyHandler] = Singleton(KivyHandler)
container[ILogger] = Singleton(Logger)
container[IApp] = Singleton(App)
container[IOperatingSystemHandler] = Singleton(OperatingSystemHandler)
container[IThreadHandler] = Singleton(ThreadHandler)
return container
# Start our app.
container = DIContainer.build_container()
container[IApp].run()