知识点
- 简略的装璜器
- 带有参数的装璜器
- 带有自定义参数的装璜器
- 类装璜器
- 装璜器嵌套
- @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 decoratortest 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_decoratordef 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_decoratordef identity(name, message): print('identity done.') print(name, message)identity('changhao', 'hello')输入:wrapper of decoratoridentity 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')输入:changhaochanghaochanghao
类装璜器
类也能够作装璜器,类装璜器次要依赖于函数 __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)@Countdef example(): print('example done.')example()example()输入:num of calls is: 1example done.num of calls is: 2example done.
这里定义了类Count,初始化时传入原函数func(),而__call__()
函数示意让变量num_calls自增1,而后打印,并且调用原函数。因而咱们第一次调用函数example()时,num_calls的值是1,而第一次调用时,值变成了2。
装璜器的嵌套
import functoolsdef my_decorator1(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('execute decorator1') func(*args, **kwargs) return wrapperdef my_decorator2(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('execute decorator2') func(*args, **kwargs) return wrapper@my_decorator1@my_decorator2def test2(message): print(message)test2('changhao')输入:execute decorator1execute decorator2changhao
@functools.wrap装璜器应用
import functoolsdef my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs) return wrapper@my_decoratordef test3(message): print(message)test3.__name__ 输入test3
通常应用内置的装璜器@functools.wrap,他会保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装璜器里)
装璜器用法实例
身份认证
import functoolsdef 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@authenticatedef post_comment(request): pass
这段代码中,定义了装璜器authenticate;而函数post_comment(),则示意发表用户对某篇文章的评论。每次调用这个函数前,都会检查用户是否处于登录状态,如果是登录状态,则容许这项操作;如果没有登录,则不容许。
日志记录
import timeimport functoolsdef 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_timedef calculate_similarity(times): pass
这里装璜器log_execution_time记录某个函数的运行工夫,并返回其执行后果。如果你想计算任何函数的执行工夫,在这个函数上方加上@log_execution_time即可。
总结
- 所谓装璜器,其实就是通过装璜器函数,来批改原函数的一些性能,使得原函数不须要批改。