使用相同的装饰器有或没有括号时Python
有什么区别?例如:
没有括号
@someDecorator
def someMethod():
pass
带括号
@someDecorator()
def someMethod():
pass
答案 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了解更多信息。