Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
26
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

Organization

PythonでDI(Dependency Injection)

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

以上です。

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
26
Help us understand the problem. What are the problem?