34
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PythonでDI(Dependency Injection)

Posted at

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

以上です。

34
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?