Posted at

PythonでDI(Dependency Injection)

More than 1 year has passed since last update.


PythonでDIする

需要はなさそうですが、たまたまPythonでDIする方法を調べたので、、、


いくつかの選択肢

Injectは2015年で開発が止まっているようです。

di-pyはあまりドキュメントが充実していないようです。

siringaは型ヒントをごにょごにょしてInjectするちょっと変態チックなやり方だったので避けました。

消去法でInjectorを試してみました。


Injectorの特徴

ドキュメントでも説明されてますが、Google Guiceライクなフレームワークになっています。

Google Guiceの説明はこの方の記事がわかりやすかったです。

Google Guice 使い方メモ

InjectやModule、Providerなどの用語もGoogle Guiceとほぼ同じなので、先にGuiceを理解する方がわかりやすいかもしれません。

(やはり型ヒントがあるとはいえ、スクリプト言語でDIをするのは理解するまでがしんどかったです)


実装例


インスタンスをDIする


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)


通常のインスタンスをDIする場合は@Injectだけで勝手にDIしてくれます。

デフォルトではシングルトンではなく、@singletonを付与することでシングルトンになるらしいです。(Guiceもデフォルトではシングルトンではない)


実装クラスのインスタンスをDIする


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)


ポイントはModuleの実装クラスでDIの設定をするところです。

シングルトンにする方法はModuleでscopeを指定することでもできるらしいです。

以上です。