1. ホーム
  2. python

[解決済み] functools.wrapsの機能は何ですか?

2022-03-21 03:14:10

質問

この記事へのコメントで 別質問に対する回答 がよくわからないとおっしゃる方がいました。 functools.wraps がやっていた。そこで、今後の参考のためにStackOverflowに記録しておくために、この質問をします。 functools.wraps は、具体的にどうするのですか?

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

デコレーターを使うということは、ある関数を別の関数に置き換えるということです。 つまり、もしデコレーターが

def logged(func):
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

という場合は

@logged
def f(x):
   """does some math"""
   return x + x * x

というのと全く同じです。

def f(x):
    """does some math"""
    return x + x * x
f = logged(f)

という関数があります。 f は関数に置き換えられます。 with_logging . 残念ながら、このことは、もしあなたが

print(f.__name__)

と表示されます。 with_logging なぜなら、それが新しい関数の名前だからです。 実際、この関数のdocstringを見ると f のため、空白になります。 with_logging はdocstringを持たないので、あなたが書いたdocstringはもうそこにはありません。 また、その関数のpydocの結果を見ると、1つの引数を取るものとしてリストアップされていません。 x 代わりに *args**kwargs というのも、with_loggingが取るのはこれだからです。

もし、デコレータを使うことで常にこのような関数に関する情報が失われるとしたら、それは深刻な問題でしょう。 そのため、私たちは functools.wraps . これは、デコレータで使用されている関数を受け取り、関数名、docstring、引数リストなどをコピーオーバーする機能を追加するものです。 そして wraps はそれ自体がデコレーターなので、次のコードは正しい処理を行います。

from functools import wraps
def logged(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

@logged
def f(x):
   """does some math"""
   return x + x * x

print(f.__name__)  # prints 'f'
print(f.__doc__)   # prints 'does some math'