functools.wraps デコレータ

高洛峰
高洛峰オリジナル
2016-11-05 14:11:191115ブラウズ

ラップは、実際には、デコレータによって引き起こされる、元の関数名が指す関数のプロパティの変更の問題を解決するために使用されます。

現時点では、デコレータは関数 func を修飾しています。は実際の関数を指しているのではなく、デコレーター内の装飾された関数を指しています

import sys

debug_log = sys.stderr

def trace(func):
        if debug_log:
                def callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res
                return callf
        else:
                return func

@trace
def square(x):
        """Calculate the square of the given number."""
        return x * x

ここでの四角は実際には呼び出しを指しています。help(square) または square.__name__ を使用して確認できます。

装飾された正方形の関数は、実際には別の関数です(関数名などの関数属性が変わります)

装飾にラップを使用する場合

def trace(func):
        if debug_log:
          @functools.wraps(func)
                def callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res
                return callf
        else:
                return func

このとき、トレースで装飾された正方形の属性は変わりませんhelp(square) で確認できます

理由: ラップの装飾コードを次のように変換します。同等のものは次のとおりです:

def trace(func):
        if debug_log:
                def _callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res

                callf = functools.update_wrapper(_callf, wrapped = func,assigned = functools.WRAPPER_ASSIGNMENTS,updated = functools.WRAPPER_UPDATES)

                return callf
        else:
                return func

update_wrapper は非常に単純なジョブを実行します。これは、ラップされたパラメータで表される関数オブジェクトです (例: square ) 一部の属性 (__name__、__doc__ など) は、パラメーター ラッパーで表される関数オブジェクトの対応する属性をオーバーライドします (例: callf、callf は単純に square 関数を呼び出すため、callf は次のラッパー関数であると言えます)四角)。

したがって、この例で、wraps デコレータを使用して callf を「装飾」した後、callf の __doc__、__name__、およびその他の属性は、トレースによって「装飾」される関数 square の属性とまったく同じになります。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。