1. ホーム
  2. python

[解決済み] PythonicなDependency Injectionの方法とは?

2023-02-19 10:03:27

質問

はじめに

Java では、依存性注入は純粋な OOP として動作します。すなわち、実装するインターフェースを提供し、フレームワークのコードで、定義されたインターフェースを実装しているクラスのインスタンスを受け取ります。

Pythonでも同じようなことができますが、Pythonの場合、この方法はオーバーヘッドが大きすぎると思います。では、Pythonの場合はどのように実装するのでしょうか?

使用例

これがフレームワークのコードだとします。

class FrameworkClass():
    def __init__(self, ...):
        ...

    def do_the_job(self, ...):
        # some stuff
        # depending on some external function

基本的な考え方

最も単純な (そしておそらく最良の?) 方法は、外部関数を FrameworkClass のコンストラクタから呼び出されるようにすることです。 do_the_job メソッドから呼び出されます。

フレームワークのコードです。

class FrameworkClass():
    def __init__(self, func):
        self.func = func

    def do_the_job(self, ...):
        # some stuff
        self.func(...)

クライアントコードです。

def my_func():
    # my implementation

framework_instance = FrameworkClass(my_func)
framework_instance.do_the_job(...)

質問

質問は短いです。これを行うために、より良い一般的に使用されるPythonic方法はありますか?または多分そのような機能をサポートしている任意のライブラリ?

UPDATE: 具体的な状況

私が、トークンを使って認証を行うマイクロウェブフレームワークを開発したとします。このフレームワークでは、いくつかの ID に対応するユーザを取得する関数が必要です。 ID .

明らかに、フレームワークはユーザーもしくはほかのアプリケーション固有のロジックについて何も知らないので、クライアントコードは認証を動作させるためにユーザーゲッター機能をフレームワークに注入しなければなりません。

どのように解決するのでしょうか?

参照 Raymond Hettinger - 超考えたスーパー! - PyCon 2015 にて、DIではなくsuperと多重継承を使う方法について議論しています。動画を全部見る時間がない場合は、15分までジャンプしてください(でも全部見ることをお勧めします)。

このビデオで説明されていることをどのように適用するか、例を挙げてみましょう。

フレームワークのコードです。

class TokenInterface():
    def getUserFromToken(self, token):
        raise NotImplementedError

class FrameworkClass(TokenInterface):
    def do_the_job(self, ...):
        # some stuff
        self.user = super().getUserFromToken(...)

クライアントコードです。

class SQLUserFromToken(TokenInterface):
    def getUserFromToken(self, token):      
        # load the user from the database
        return user

class ClientFrameworkClass(FrameworkClass, SQLUserFromToken):
    pass

framework_instance = ClientFrameworkClass()
framework_instance.do_the_job(...)

これはPython MROが(super()が使われていれば)getUserFromTokenクライアントメソッドが呼ばれることを保証するため、動作します。Python 2.xを使用している場合は、コードを変更する必要があります。

ここでの1つの付加的な利点は、クライアントが実装を提供しない場合、これは例外を発生させるということです。

もちろん、これは本当の依存性注入ではなく、多重継承とミキシンですが、あなたの問題を解決するためのPythonicな方法です。