Python の二種類のデコレータ2022年05月26日 11時29分57秒

Python には二種類のデコレータがある。まずは、引数無しのデコレータ。そして、引数ありのデコレータ。

引数無しのデコレータと functools.wraps の解説があり、引数ありのデコレータの解説がある。

簡単にまとめると、デコレータとは関数を引数に実行される関数の呼び出し。実例を見た方が断然分かりやすい。コードは上記のところから引用。

デコレータのこの表記は、

@logged
def f(x):
   """does some math"""
   return x + x * x
以下の表記と同じ。
def f(x):
    """does some math"""
    return x + x * x
f = logged(f)
関数の実装を置き換えている。

この置き換え時に、Python の内部変数名も替えておくと色々と便利。そこで functools.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'

それ自体が引数を取るデコレータだとかなりややこしくなって、関数を返す関数を二重で行う必要がある。理屈としては、

@decorator_with_args(arg)
def foo(*args, **kwargs):
    pass
foo = decorator_with_args(arg)(foo)
に成るから、一段深くなる。

最終的に、以下の定型文になる。

def decorator_factory(argument):
    def decorator(function):
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            result = function(*args, **kwargs)
            more_funny_stuff()
            return result
        return wrapper
    return decorator

何度見ても折り込み等で混乱する。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://uyota.asablo.jp/blog/2022/05/26/9494198/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。