There seems to be no demand, but I happened to find out how to DI with Python, so ...
Inject seems to have stopped developing in 2015. di-py doesn't seem to be very well documented. I avoided siringa because it was a bit of a metamorphic way to inject type hints.
I tried Injector by elimination method.
As explained in the documentation, it's a Google Guice -like framework. The explanation of Google Guice was easy to understand in this article. Google Guice usage memo
Terms such as Inject, Module, and Provider are almost the same as Google Guice, so it may be easier to understand Guice first. (Although there are still type hints, doing DI in a scripting language was hard to understand)
todo_usecase.py
@singleton
class TodoUseCase:
def register(self, todo: Todo) - > None:
print("call todo_usecase.register")
todo_controller.py
@singleton
class TodoController:
@inject
def __init__(self, todo_usecase: TodoUseCase) -> None:
self.todo_usecase = todo_usecase
def create_todo(self, todo: Todo) -> None:
self.todo_usecase.register(todo)
if __name__=='__main__':
injector = Injector()
todo_controller: TodoController = injector.get(TodoController)
todo: Todo = Todo()
todo_controller.create_todo(todo)
If you want to DI a normal instance, just @Inject
will do the DI for you.
By default, it seems to be a singleton by giving @singleton
instead of a singleton. (Guice is also not a singleton by default)
todo_repository.py
class TodoRepository:
@abstractmethod
def register(self, todo: Todo) -> None:
raise NotImplementedError
todo_datasource.py
class TodoDataSource(TodoRepository):
def register(self, todo: Todo) -> None:
print("call todo_datasource.register")
todo_usecase.py
@singleton
class TodoUseCase:
@inject
def __init__(self, todo_repository: TodoRepository) -> None:
self.todo_repository = todo_repository
def register(self, todo: Todo) -> None:
self.todo_repository.register(todo=todo)
class TodoDIModule(Module):
def configure(self, binder):
binder.bind(TodoRepository, to=TodoDataSource, scope=singleton)
if __name__=='__main__':
injector = Injector([TodoDIModule()])
todo_use_case: TodoUseCase = injector.get(TodoUseCase)
todo: Todo = Todo()
todo_use_case.register(todo)
The point is to set DI in the implementation class of Module. It seems that the method of making it a singleton can also be done by specifying the scope in Module.
that's all.
Recommended Posts