使用带或不带括号的python decorator

时间:2016-02-23 08:43:01

标签: python decorator

使用相同的装饰器有或没有括号Python有什么区别?例如:

没有括号

@someDecorator
def someMethod():
    pass

带括号

@someDecorator()
def someMethod():
    pass

4 个答案:

答案 0 :(得分:50)

第一个代码段中的

someDecorator是常规装饰器:

@someDecorator
def someMethod():
    pass

相当于

someMethod = someDecorator(someMethod)

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

@someDecorator()
def someMethod():
    pass

相当于

someMethod = someDecorator()(someMethod)

正如Duncan在评论中指出的那样,一些装饰者被设计为双向工作。这是这种装饰器的一个非常基本的实现:

def someDecorator(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是一个更复杂的例子。

答案 1 :(得分:2)

如果您有一个可以使用或不使用参数的装饰器,则可以在装饰器上使用以下装饰器 使其可以在带或不带括号的情况下使用,如下所示:

>>> @omittable_parentheses(allow_partial=True)
... def multiplier(multiply_by=2):
...     def decorator(func):
...         def multiplying_wrapper(*args, **kwargs):
...             return multiply_by * func(*args, **kwargs)
...         return multiplying_wrapper
...     return decorator
...
>>> @multiplier
... def no_parentheses():
...     return 2
...
>>> no_parentheses()
4
>>> @multiplier()
... def parentheses():
...     return 2
...
>>> parentheses()
4
>>> @multiplier(3)
... def parameter():
...     return 2
...
>>> parameter()
6

如果给出了allow_partial=True,则生成的装饰器也可以与partial一起使用:

>>> from functools import partial
>>> multiply_by_3 = partial(multiplier, multiply_by=3)
>>>
>>> @multiply_by_3
... def partial_no_parentheses():
...     return 2
...
>>> partial_no_parentheses()
6
>>> @multiply_by_3()
... def partial_parentheses():
...     return 2
...
>>> partial_parentheses()
6

装饰代码:

from functools import wraps

def omittable_parentheses(maybe_decorator=None, /, allow_partial=False):
    """A decorator for decorators that allows them to be used without parentheses"""
    def decorator(func):
        @wraps(decorator)
        def wrapper(*args, **kwargs):
            if len(args) == 1 and callable(args[0]):
                if allow_partial:
                    return func(**kwargs)(args[0])
                elif not kwargs:
                    return func()(args[0])
            return func(*args, **kwargs)
        return wrapper
    if maybe_decorator is None:
        return decorator
    else:
        return decorator(maybe_decorator)

作为奖励,此修饰器修饰器本身可以带或不带括号使用!

答案 2 :(得分:0)

一些实际工作的代码,你在装饰器中使用arg:

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

答案 3 :(得分:0)

简而言之,装饰器允许将丰富的功能添加到一组函数和类中,而无需进行任何修改。

了解@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只是一个装饰器。请记住,有些装饰器是双向工作的。

所以现在您可能想知道为什么当以前的版本看起来更简单时,我们有这两种情况。答案是,如果您要将参数传递给装饰器,则使用@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了解更多信息。