web-dev-qa-db-ja.com

pythonデコレータを括弧の有無にかかわらず使用する

Pythonでは、同じデコレータを使用することの違いは何ですか括弧ありとなし

例えば:

括弧なし:

@some_decorator
def some_method():
    pass

括弧付き:

@some_decorator()
def some_method():
    pass
47
BendEg

some_decorator最初のコードスニペットは通常のデコレータです:

@some_decorator
def some_method():
    pass

に相当

some_method = some_decorator(some_method)

一方、 some_decorator 2番目のコードスニペットでは、デコレータを返す呼び出し可能オブジェクトです。

@some_decorator()
def some_method():
    pass

に相当

some_method = some_decorator()(some_method)

Duncanのコメントで指摘されているように、一部のデコレータは双方向で機能するように設計されています。このようなデコレータのかなり基本的な実装は次のとおりです。

def some_decorator(arg=None):
    def decorator(func):
        def wrapper(*a, **ka):
            return func(*a, **ka)
        return wrapper

    if callable(arg):
        return decorator(arg) # return 'wrapper'
    else:
        return decorator # ... or 'decorator'

pytest.fixture はより複雑な例です。

51
vaultah

簡単に言うと、デコレータを使用すると、関数やクラスのグループにまったく変更を加えることなく、それらに機能を追加できます。

_@some_decorator_と@some_decorator()の違いを理解するための鍵は、前者はデコレータであり、後者はデコレータを返す関数(または呼び出し可能)であることです

各ケースの実装を見ると、違いを理解するのに役立つと思います。

_@some_decorator_

_def some_decorator(func):
    def wrapper(func):
        return func(*args, **kwargs)
    return wrapper
_

アプリケーション:

_@some_decorator
def some_method():
    pass
_

同等:

_some_method = some_decorator(some_method)
_

@some_decorator()

_def some_decorator():
    def decorator(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorator
_

アプリケーション:

_@some_decorator()
def some_method():
    pass
_

同等:

_some_method = some_decorator()(some_method)
_

_some_decorator_が単なるデコレータであるのに対して、@some_decorator()はデコレータを返す関数であることが簡単にわかるようになりました。一部のデコレータは双方向で機能するように作成されていることに注意してください。

したがって、以前のバージョンの方が単純に見えるのに、なぜこの2つのケースがあるのか​​疑問に思われるかもしれません。答えは、デコレータに引数を渡したい場合、@some_decorator()を使用するとこれが可能になるということです。実際のコードをいくつか見てみましょう。

_def some_decorator(arg1, arg2):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(arg1)
            print(arg2)
            return func(*args, **kwargs)
        return wrapper
    return decorator
_

アプリケーション:

_@some_decorator('hello', 'bye')
def some_method():
    pass
_

同等:

_some_method = some_decorator('hello', 'bye')(some_method)
_

注:デコレータは関数またはクラスとして実装できることを言及する価値があると思います。詳細は this を確認してください。

0
lmiguelvargasf

デコレーター内で引数を使用する実際に機能するコード:

def someDecorator(arg=None):
    def decorator(func):
        def wrapper(*a, **ka):
            if not callable(arg):
                print (arg)
                return func(*a, **ka)
            else:
                return 'xxxxx'
        return wrapper

    if callable(arg):
        return decorator(arg) # return 'wrapper'
    else:
        return decorator # ... or 'decorator'

@someDecorator(arg=1)
def my_func():
    print('aaa')

@someDecorator
def my_func1():
    print('bbb')

if __name__ == "__main__":
    my_func()
    my_func1()

出力は次のとおりです。

1
aaa