1. ホーム
  2. python

オプションの引数を持つデコレータの作成 [重複]。

2023-12-05 11:52:37

質問

from functools import wraps

def foo_register(method_name=None):
    """Does stuff."""
    def decorator(method):
        if method_name is None:
            method.gw_method = method.__name__
        else:
            method.gw_method = method_name
        @wraps(method)
        def wrapper(*args, **kwargs):
            method(*args, **kwargs)
        return wrapper
    return decorator

例 以下は my_functionfoo_register にするのではなく decorator .

@foo_register
def my_function():
    print('hi...')

例 以下は期待通りに動作します。

@foo_register('say_hi')
def my_function():
    print('hi...')

もし、両方のアプリケーションで正しく動作させたいのであれば (一方は method.__name__ を使うものと、名前を渡すもの) の両方が正しく動作するように、私は foo_register の内部で、最初の引数がデコレータであるかどうかを確認し、 もしそうなら return decorator(method_name) (代わりに return decorator ). このような "check to see it's a callable" は、非常にハッキング的だと思われます。このような複数回使用できるデコレーターを作成するためのより良い方法はありますか?

追伸:デコレータが呼び出されることを要求できることはすでに知っていますが、それは"解決策"ではありません。私は API が自然に感じられるようにしたいのです。私の妻は装飾が好きなので、それを台無しにしたくありません。

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

グレン - その時はそうするしかなかったんだ。魔法のような方法でなくてよかったと思います。私はそれが嫌いなんです。

ということで、私なりの答えです(メソッド名は上記と異なりますが、コンセプトは同じです)。

from functools import wraps

def register_gw_method(method_or_name):
    """Cool!"""
    def decorator(method):
        if callable(method_or_name):
            method.gw_method = method.__name__
        else:
            method.gw_method = method_or_name
        @wraps(method)
        def wrapper(*args, **kwargs):
            method(*args, **kwargs)
        return wrapper
    if callable(method_or_name):
        return decorator(method_or_name)
    return decorator

使用例(どちらのバージョンも同じように動作します)。

@register_gw_method
def my_function():
    print('hi...')

@register_gw_method('say_hi')
def my_function():
    print('hi...')