2

バックグラウンド

ファイルの読み取りまたはファイルへの書き込みを行ういくつかの関数を備えたライブラリがあります。各関数は、ファイルオブジェクトまたはファイル名のいずれかとして、最初の引数としてファイルを受け入れます。したがって、すべての関数の最初のコードは、次のように同じです。

if isinstance(f, str):
    file_obj = open(f, 'w')
else:
    file_obj = f

これをデコレータで一度記述して、すべての関数をラップすることができ、繰り返す必要はないと思いました。(同じデコレータ内にコンテキストマネージャインターフェイスを実装することも考えています。)

したがって、これを行うと、関数は次のようになります。

@file_aware('w')
def function(f, *args, **kwargs):
    """Do stuff. `f` can be file object or file name"""
    for line in f:
       ....

質問

私の懸念は、関数のdocstringがその下のコードに対応していないことです。(装飾された関数のdocstringをで保持することを計画していfunctools.wrapsます。)それはコードの可読性/保守性/透明性を低下させますか?私が理解していることから、デコレータは簡単に行き来できますが、同時にこれはAPIを少し変更します(機能を削除する予定はありません)。この場合の「ベストプラクティス」の方法は何ですか?

デコレータ内でdocstringを自動的に処理することを考えることができますが、次のようになります。

  • それは最も自然なことではありません。
  • これはオンラインドキュメントにのみ意味があり、誰かがソースコードを読むのを助けません(むしろ反対です)。
4

1 に答える 1

3

1 つのオプションは、docstring をデコレータに渡すことです。そうすれば、ソース コードを読み取るための関数定義によって docstring を保持できますが、デコレータを変更または削除しても、不適切な docstring になることはありません。

例えば:

@file_aware(docstring="Do stuff. `f` can be file object or file name", mode="r")
def function(f, *args, **kwargs):
    for line in f:
       ....

デコレータfile_awareは次のようになります。

def file_aware(docstring, mode):
    def deco(func):
        @functools.wraps(func)
        def wrapped(f, *args, **kwargs):
            if isinstance(f, str):
                file_obj = open(f, mode)
            else:
                file_obj = f
            return func(file_obj, *args, **kwargs)
        wrapped.__doc__ = docstring
        return wrapped
    return deco
于 2012-12-18T17:34:41.720 に答える