使用带或不带括号的python decorator

Ben*_*dEg 44 python decorator

__CODE__使用带括号或不带括号的相同装饰器什么区别?例如:

没有括号

@some_decorator
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

括号

@some_decorator()
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

vau*_*tah 51

some_decorator 在第一个代码片段中是一个常规装饰器:

@some_decorator
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

相当于

some_method = some_decorator(some_method)
Run Code Online (Sandbox Code Playgroud)

另一方面,some_decorator在第二个代码片段中是一个返回装饰器的可调用代码:

@some_decorator()
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

相当于

some_method = some_decorator()(some_method)
Run Code Online (Sandbox Code Playgroud)

正如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'
Run Code Online (Sandbox Code Playgroud)

pytest.fixture 是一个更复杂的例子.

  • 可能值得添加你的答案,提到一些装饰器被编写为双向工作,例如`@ pytest.fixture`可以直接用作装饰器,或者可能用一些命名参数调用,在这种情况下它返回一个装饰器. (10认同)
  • 另请注意,由于 [decopatch](https://smarie.github.io/python-decopatch/),邓肯提到的技巧现在可以完全自动化。顺便说一句,我是作者:) (2认同)

lmi*_*asf 5

简而言之,装饰器允许向一组函数和类添加丰富的特性,而无需对其进行任何修改。

关键要了解的差值之间@some_decorator以及@some_decorator()在于前者是装饰,而后者是一个函数(或可调用)返回一个装饰

我相信看到每个案例的实现有助于理解差异:

@some_decorator

def some_decorator(func):
    def wrapper(func):
        return func(*args, **kwargs)
    return wrapper
Run Code Online (Sandbox Code Playgroud)

应用:

@some_decorator
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

等价:

some_method = some_decorator(some_method)
Run Code Online (Sandbox Code Playgroud)

@some_decorator()

def some_decorator():
    def decorator(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorator
Run Code Online (Sandbox Code Playgroud)

应用:

@some_decorator()
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

等价:

some_method = some_decorator()(some_method)
Run Code Online (Sandbox Code Playgroud)

请注意,现在更容易看出这@some_decorator()是一个返回装饰器的函数,而some_decorator它只是一个装饰器。请记住,一些装饰器被编写为双向工作。

所以现在你可能想知道为什么我们有这两种情况,而前一个版本看起来更简单。答案是,如果您想将参数传递给装饰器, using@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
Run Code Online (Sandbox Code Playgroud)

应用:

@some_decorator('hello', 'bye')
def some_method():
    pass
Run Code Online (Sandbox Code Playgroud)

等价:

some_method = some_decorator('hello', 'bye')(some_method)
Run Code Online (Sandbox Code Playgroud)

注意:我认为值得一提的是,装饰器可以实现为函数或类。检查这个以获取更多信息。