详解Python实现同时支持带调用和不调用带装饰器
作者:临渊
一般来说,不带参数装饰器,再使用时不加括号,带参数的装饰器使用时必须加括号,这篇文章主要介绍了Python实现同时支持带调用和不调用带装饰器的相关知识,需要的朋友可以参考下
一般来说,不带参数装饰器,再使用时不加括号,带参数的装饰器使用时必须加括号。例如
- 不带参装饰器
def info(func): # 装饰器,参数接收一个函数,返回一个函数 @functools.wraps(func) def wrapper(*args, **kwargs): # 与原函数功能一致,支持任意参数 print(f'调用函数: {func.__name__} 参数:{args} {kwargs}') return func(*args, **kwargs) # 内部包裹调用原函数 return wrapper # 返回和原函数功能一致的函数 @info # 使用时不加括号 def add(a, b): return a + b
- 带参数的装饰器(返回装饰器的函数)
def info(show_result=True): def _info(func): # 装饰器,参数接收一个函数,返回一个函数 @functools.wraps(func) def wrapper(*args, **kwargs): # 与原函数功能一致,支持任意参数 print(f'调用函数: {func.__name__} 参数:{args} {kwargs}') start_time = time.time() result = func(*args, **kwargs) # 内部包裹调用原函数 if show_result is True: print(f'调用结果: {result} 耗时: {time.time()-start_time}') return result return wrapper # 返回替换后的新函数 return _info @info() # 即使使用默认参数也必须加括号调用(因为调用后才能得到装饰器) def add(a, b): return a + b
注意: 带参数装饰器虽然通过参数支持定制,但是使用时必须加括号,用户很容易遗漏或分不清是否需要加括号
能不能像@pytest.fixture那样,既可以不带参数,也可以带参数使用呢,例如:
import pytest @pytest.fixture def a(): ... @pytest.fixture() def b(): ... @pytest.fixture(scope='module') def c(): ...
这就要求,我们装饰器外部函数,即可以本身作为一个装饰器(接收一个原函数,返回一个同功能函数),也可以根据参数调用后返回一个装饰器,实现如下:
def info(func=None, show_result=False): # 第一个参数为函数 def _info(func): # 装饰器,参数接收一个函数,返回一个函数 @functools.wraps(func) def wrapper(*args, **kwargs): # 与原函数功能一致,支持任意参数 print(f'调用函数: {func.__name__} 参数:{args} {kwargs}') start_time = time.time() result = func(*args, **kwargs) # 内部包裹调用原函数 if show_result is True: print(f'调用结果: {result} 耗时: {time.time()-start_time}') return result return wrapper # 返回替换后的新函数 if func is not None: # 不带括号(作为装饰器)使用时 return _info(func) # 返回 同功能函数wrapper(即_info的调用结果) return _info # 否则,带括号调用(作为返回装饰器的函数)使用时,返回装饰器 _info @info # 即使使用默认参数也必须加括号调用(因为调用后才能得到装饰器) def add(a, b): return a + b @info() def sub(a, b): return a - b @info(show_result=True) def mul(a, b): return a * b
注意:1. 在使用装饰器info()不能手动指定第一个参数func=...
2. 在指定参数时,只能按key=value形式给出
到此这篇关于Python实现同时支持带调用和不调用带装饰器的文章就介绍到这了,更多相关python带调用和不调用带装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!