使用带括号或不带括号的python装饰器
在Python中,使用带括号和不带括号的同一个修饰符有什么区别 例如: 不带括号:使用带括号或不带括号的python装饰器,python,decorator,Python,Decorator,在Python中,使用带括号和不带括号的同一个修饰符有什么区别 例如: 不带括号: @some_decorator def some_method(): pass @some_decorator() def some_method(): pass 带括号: @some_decorator def some_method(): pass @some_decorator() def some_method(): pass some_decorator在第一个代
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
带括号:
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
some_decorator
在第一个代码段中是一个常规的decorator:
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
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'
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()
相当于
some_method = some_decorator(some_method)
另一方面,第二个代码段中的some_decorator是返回decorator的可调用函数:
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
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'
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()
相当于
some_method = some_decorator()(some_method)
正如邓肯在评论中指出的,一些装饰师被设计成双向工作。下面是这种装饰器的一个非常基本的实现:
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
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'
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()
是一个更复杂的示例。使用arg inside decorator的一些实际工作代码:
@some_decorator
def some_method():
pass
@some_decorator()
def some_method():
pass
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'
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
简而言之,修饰符允许向函数组和类组添加丰富的特性,而无需对其进行任何修改 理解
@some_decorator
和@some_decorator()
之间区别的关键在于前者是decorator,而后者是返回decorator的函数(或可调用的函数)
我认为,看到每个案例的实施有助于理解差异:
@some_decorator
应用程序:
@some_decorator
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
等效性:
@some_decorator
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
@some\u decorator()
应用程序:
@some_decorator
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
等效性:
@some_decorator
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
注意,现在更容易看到@some\u decorator()
是一个返回decorator的函数,而some\u decorator
只是一个decorator。请记住,有些装饰师是双向工作的
所以现在你可能想知道为什么我们有这两种情况,而前一个版本似乎更简单。答案是,如果您想将参数传递给装饰器,使用@some\u 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
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
等效性:
@some_decorator
def some_method():
pass
some_method = some_decorator(some_method)
@some_decorator()
def some_method():
pass
some_method = some_decorator()(some_method)
@some_decorator('hello', 'bye')
def some_method():
pass
some_method = some_decorator('hello', 'bye')(some_method)
注意:我认为值得一提的是,装饰器可以作为函数或类实现。查看更多信息。如果您有一个可以使用参数或不使用参数的装饰器,您可以在装饰器上使用以下装饰器,使其可以使用括号或不使用括号,如下所示:
>@ommittable\u括号(allow\u partial=True)
... def乘数(乘以=2):
... def装饰器(func):
... def乘_包装(*args,**kwargs):
... 返回乘以*func(*args,**kwargs)
... 返回乘法包装器
... 返回装饰器
...
>>>@乘数
... def无括号():
... 返回2
...
>>>无括号()
4.
>>>@multiplier()
... def括号():
... 返回2
...
>>>括号()
4.
>>>@乘数(3)
... def参数():
... 返回2
...
>>>参数()
6.
如果给定了allow\u partial=True
,则生成的装饰程序也将使用partial
:
>>从functools导入部分
>>>乘以3=部分(乘数,乘以3)
>>>
>>>@乘以3
... def partial_no_括号():
... 返回2
...
>>>部分括号()
6.
>>>@乘以3()
... def部分括号()
... 返回2
...
>>>部分括号()
6.
装饰代码:
从functools导入包装
def省略表的括号(可能是decorator=None,/,allow\u partial=False):
“”“允许在没有括号的情况下使用装饰器的装饰器”“”
def装饰器(func):
@包装(装饰)
def包装(*args,**kwargs):
如果len(args)==1且可调用(args[0]):
如果允许_部分:
返回函数(**kwargs)(参数[0])
elif not kwargs:
return func()(参数[0])
返回函数(*args,**kwargs)
返回包装器
如果您的decorator没有:
返回装饰器
其他:
返回装饰器(可能是装饰器)
作为奖励,这个decorator decorator本身可以使用括号,也可以不使用括号 这些不是大括号,而是圆括号。大括号是
{}
@DanielRoseman很好的提示,经常在寻找正确的单词时苦苦挣扎……下面是一个很好的答案。值得指出的是,这一区别与foo
和foo()
之间的区别是一样的,包括不在装饰器中。值得补充的是,有些装饰器是双向工作的,例如@pytest。fixture
可以直接用作装饰器,或者使用一些命名参数调用,在这种情况下它返回一个装饰器。可调用装饰器的意义是什么?在AICT中,someDecorator()
将始终返回相同的内容,因为它不接受任何参数(除非someDecorator
持有状态)。所以我假设可调用的装饰器持有一个状态?还要注意,Duncan提到的技巧现在可以完全自动化,多亏了。顺便说一句,我是作者:)这是一个非常好的技巧,但它并没有真正回答最初的问题,即使用括号与不使用括号有什么区别。