web-dev-qa-db-ja.com

署名変更デコレーター:追加の引数を適切に文書化する

カスタムデコレータがあり、それが修飾された関数のdocstringを適切に処理するとします。問題は、私のデコレータが引数を追加することです。

from functools import wraps

def custom_decorator(f):
    @wraps(f)
    def wrapper(arg, need_to_do_more):
        '''
        :param need_to_do_more: if True: do more
        '''
        args = do_something(arg)

        if need_to_do_more:
            args = do_more(args)

        return f(args)

    return wrapper

引数が実際には装飾された関数に渡されず、ラッパーによって使用されていることがわかります。

追加の引数の文書化を適切に処理するにはどうすればよいですか?ラッパーが追加の引数を取ることは良い習慣ですか、それとも避けるべきですか?

または、次のような別のソリューションを使用する必要があります:

  • ラッパーを単純な高次関数にし、それが呼び出す関数を3番目の引数として渡す
  • ラッパーを2つの別々の関数にリファクタリングしますか?
6
vikingr

デコレータを使用してメソッドのシグネチャを変更することは、ほとんどの場合違反するものです 最小の驚きの原則

最小驚きの原則では、操作の名前と他の手がかりに基づいて、一部の操作を実行した結果は明白で一貫性があり、予測可能である必要があると述べています。

私が思いつく可能性のある例外は:

  • その名前のデコレータは、メソッドシグネチャが変更されたことを明確に述べています。そのようなデコレータの例は @property です。
  • 装飾されたメソッドは、クライアントコードによって直接呼び出されることを意図していません
  • デコレータは、ある種の適応に使用されます( アダプタパターン など)。

それにもかかわらず、通常、デコレータは通常、関数をデコレートするために実装されます( Decorator pattern のように、デコレータ機能の作成者 この類似性に反対 )。パラメータ)は変更されません。

新しいパラメーターを暗黙的に追加する代わりに、これを明示的にすることを提案します。装飾された関数は、パラメーターのリストでそのようなパラメーターを宣言する必要がありますこのメソッドの説明SO answer を使用して関数のパラメーター名を確認し、装飾された関数にそのようなパラメーターがない場合は例外をスローできます。

暗黙的なパラメータまたは必須のパラメータは、デコレータのdocstring(例ではcustom_decorator)で説明する必要があります。返された関数(例ではwrapper)で@wrapsデコレータを使用すると、__doc__属性が関数fからコピーされ、wrapper

2
Dawid Pytel