知识点
- 简略的装璜器
- 带有参数的装璜器
- 带有自定义参数的装璜器
- 类装璜器
- 装璜器嵌套
- @functools.wrap 装璜器应用
根底应用
简略的装璜器
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper()
def test():
print('test done.')
test = my_decorator(test)
test
输入:wrapper of decorator
test done.
这段代码中,变量 test 指向了外部函数 wrapper(), 而外部函数 wrapper()中又会调用原函数 test(),因而最初调用 test()时,就会打印 ’wrapper of decorator’ 而后输入 ‘test done.’
这里的函数 my_decorator()就是一个装璜器,它把真正须要执行的函数 test()包裹在其中,并且扭转了它的行为,然而原函数 test()不变。
上述代码在 Python 中更简略、更优雅的示意:
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper()
@my_decorator
def test():
print('test done.')
test
这里的 @, 咱们称为语法糖,@my_decorator 就相当于后面的 test=my_decorator(test)语句
如果程序中又其余函数须要相似装璜,只须要加上 @decorator 就能够,进步函数的反复利用和程序可读性
带有参数的装璜器
def args_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
@args_decorator
def identity(name, message):
print('identity done.')
print(name, message)
identity('changhao', 'hello')
输入:wrapper of decorator
identity done.
changhao hello
通常状况下,会把 args 和*kwargs,作为装璜器外部函数 wrapper() 的参数。示意承受任意数量和类型的参数
带有自定义参数的装璜器
定义一个参数,示意装璜器外部函数被执行的次数,能够写成这个模式:
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(3)
def showname(message):
print(message)
showname('changhao')
输入:changhao
changhao
changhao
类装璜器
类也能够作装璜器,类装璜器次要依赖于函数 __call__
每当调用一个示例时,函数 __call__()
就会被执行一次。
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs)
@Count
def example():
print('example done.')
example()
example()
输入:num of calls is: 1
example done.
num of calls is: 2
example done.
这里定义了类 Count,初始化时传入原函数 func(),而 __call__()
函数示意让变量 num_calls 自增 1,而后打印,并且调用原函数。因而咱们第一次调用函数 example()时,num_calls 的值是 1,而第一次调用时,值变成了 2。
装璜器的嵌套
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 test2(message):
print(message)
test2('changhao')
输入:execute decorator1
execute decorator2
changhao
@functools.wrap 装璜器应用
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 test3(message):
print(message)
test3.__name__
输入
test3
通常应用内置的装璜器 @functools.wrap,他会保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装璜器里)
装璜器用法实例
身份认证
import functools
def authenticate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
request = args[0]
if check_user_logged_in(request):
return func(*args, **kwargs)
else:
raise Exception('Authentication failed')
return wrapper
@authenticate
def post_comment(request):
pass
这段代码中,定义了装璜器 authenticate;而函数 post_comment(),则示意发表用户对某篇文章的评论。每次调用这个函数前,都会检查用户是否处于登录状态,如果是登录状态,则容许这项操作;如果没有登录,则不容许。
日志记录
import time
import functools
def log_execution_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
res = func(*args, **kwargs)
end = time.perf_counter()
print('{} took {} ms'.format(func.__name__, (end - start) * 1000))
return wrapper
@log_execution_time
def calculate_similarity(times):
pass
这里装璜器 log_execution_time 记录某个函数的运行工夫,并返回其执行后果。如果你想计算任何函数的执行工夫,在这个函数上方加上 @log_execution_time 即可。
总结
- 所谓装璜器,其实就是通过装璜器函数,来批改原函数的一些性能,使得原函数不须要批改。