python 装饰器的基本使用

时间:2021-05-23

知识点

  • 简单的装饰器
  • 带有参数的装饰器
  • 带有自定义参数的装饰器
  • 类装饰器
  • 装饰器嵌套
  • @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

类装饰器

类也可以作装饰器,类装饰器主要依赖于函数 __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即可。

总结

所谓装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

以上就是python 装饰器的基本使用的详细内容,更多关于python 装饰器的资料请关注其它相关文章!

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章