Help us understand the problem. What is going on with this article?

PythonでDI(Dependency Injection)

More than 3 years have 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を指定することでもできるらしいです。

以上です。

zozotech
70億人のファッションを技術の力で変えていく
https://tech.zozo.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away