装饰器
一、简单装饰器
def my_decorator(func):
def wrapper():
print('wrapper of decorator!')
func()
return wrapper
def greet():
print('halo world!')
greet = my_decorator(greet)
greet()
# 输出
wrapper of decorator!
hello world!
@my_decorator
def greet2():
print('halo world2!')
greet2()
# 输出
wrapper of decorator!
hello world2!
这里my_decorator()为装饰器,将greet()包含在其中,改变了greet函数的行为,但是原函数greet并没变。不改变原函数的情况下,改变函数的行为。
调用方法:
1、像greet函数中进行调用
greet = my_decorator(greet) greet()
2、像greet2函数中进行调用 @my_decorator
这里的@称之为语法糖
二、带有参数的装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator!')
func(*args, **kwargs)
return wrapper
@my_decorator
def greet(message):
print(message)
greet('halo world!')
# 输出
wrapper of decorator!
halo world!
三、带有自定义参数的装饰器
举例:如果想让一个函数执行多次,可以写成
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(4)
def greet(message):
print(message)
greet('hello world')
# 输出:
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
四、原函数的元信息
greet.__name__
## 输出
wrapper
以上可知,原函数元信息改变,greet函数被wrapper函数取代
解决:采用内置装饰器@functools.wraps(func)
,将原函数的元信息拷贝到对应装饰器函数
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator!')
func(*args, **kwargs)
return wrapper
@my_decorator
def greet(message):
print(message)
greet.__name__
# 输出
'greet'
五、类装饰器
主要依赖于函数_call_()
import time
class TimeCount:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start_time = time.time()
self.func()
end_time = time.time()
print(f'执行函数时间为:{start_time-end_time}')
@TimeCount
def greet():
time.sleep(2)
greet()
六、装饰器嵌套
@decorator1
@decorator2
@decorator3
def func():
...
执行顺序:从里向外
decorator1(decorator2(decorator3(func)))
import functools
def my_decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator1')
func(*args, **kwargs)
return wrapper
def my_decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator2')
func(*args, **kwargs)
return wrapper
@my_decorator1
@my_decorator2
def greet(message):
print(message)
greet('hello world')
# 输出
execute decorator1
execute decorator2
hello world
七、应用场景
身份认证、日志、缓存、输入合法性检查等