什么是装饰器
装饰器就是把一个函数当参数传到另一个函数(也可以是可迭代对象 callable
)中然后再回调, @
是其语法糖
常见的四种形态的装饰器
1. 不带参数的装饰器
def logger(func):
def wrapper(*args, **kwargs):
print(f'prepare to run {func.__name__}')
func(*args, **kwargs)
print('finished...')
return wrapper
@logger
def add(x, y):
print(f'{x} + {y} = {x+y}')
add(1, 2)
# Result:
# prepare to run add
# 1 + 2 = 3
# finished...
2. 带参数的装饰器
def logger(level='INFO'):
def wrapper(func):
def handle(*args, **kwargs):
print(f'{level}: prepare to run {func.__name__}')
func(*args, **kwargs)
print('finished...')
return handle
return wrapper
@logger('ERROR')
def add(x, y):
print(f'{x} + {y} = {x+y}')
add(1, 2)
# Result:
# ERROR: prepare to run add
# 1 + 2 = 3
# finished...
3. 不带参数的类装饰器
不带参数时,初始化的参数为被装饰函数
,即两层结构。
class logger(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f'prepare to run {self.func.__name__}')
return self.func(*args, **kwargs)
@logger
def add(x, y):
print(f'{x} + {y} = {x+y}')
add(1, 2)
# Result:
# prepare to run add
# 1 + 2 = 3
4. 带参数的类装饰器
带参数时,初始化的参数为装饰函数的参数
,即三层结构。
class logger(object):
def __init__(self, level="INFO"):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'{self.level}: prepare to run {func.__name__}')
return func(*args, **kwargs)
return wrapper
@logger('ERROR')
def add(x, y):
print(f'{x} + {y} = {x+y}')
add(1, 2)
# Result:
# ERROR: prepare to run add
# 1 + 2 = 3
使用装饰器的注意事项
1. 使用 functools 中的 wraps
保持被装饰函数签名, 否则签名为装饰器对象
from functools import wraps
def wrapper(func):
@wraps(func)
def handle():
pass
return handle
@wrapper
def wrapped():
pass
print(wrapped.__name__)
# Result:
# wrapped
2. 装饰顺序
执行顺序: wrapper1 > wrapper2 (wrapper1 装饰 wrapper2, wrapper2 装饰 func)
@wrapper1
@wrapper2
def func():
pass
3. 闭包
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count = wrapper.count + 1
res = func(*args, **kwargs)
print("{0} has been used: {1} x".format(func.__name__, wrapper.count))
return res
wrapper.count = 0
return wrapper
@counter
def system_out(string):
print(string)
system_out("A")
system_out("B")
# Result:
# A
# system_out has been used: 1x
# B
# system_out has been used: 2x
装饰器常用场景及代码实现
日志打印,权限控制,处理函数超时(待更新)
参考
https://stackoverflow.com/que...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。