python 装饰器的基本使用
作者:changhao 发布时间:2021-04-01 07:12:50
知识点
简单的装饰器
带有参数的装饰器
带有自定义参数的装饰器
类装饰器
装饰器嵌套
@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
类装饰器
类也可以作装饰器,类装饰器主要依赖于函数 __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即可。
总结
所谓装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。
来源:https://segmentfault.com/a/1190000038959829


猜你喜欢
- 如下所示:ljust(len,str)字符向左对齐,用str补齐长度rjust(len,str)字符向右对齐,用str补齐长度rjust(l
- 如下所示:import arcpy... from arcpy import env... env.workspace="C:\\
- 写本篇文章之前其实也关注过vue中的一个关于加载动态组件is的API,最开始研究它只是用来实现一个tab切换的功能,使用起来也蛮不错的。is
- 本文实例讲述了python使用PyGame绘制图像并保存为图片文件的方法。分享给大家供大家参考。具体实现方法如下:''
- 本文实例讲述了php设计模式之装饰模式。分享给大家供大家参考,具体如下:介绍装饰者模式(Decorator Pattern)允许你向一个现有
- 前言我们在上一期学习了关于Python 迭代器Iterator详情相关的概念,满足迭代器需要符合两个条件实现__iter__()方
- 当产品走到HTML Coding这块,多浏览器的测试是很重要,也很麻烦的一个环节。现在大家主要是保证IE6,7及Firefox的一致。bro
- golang这个语言用起来和java、 c#之类语言差不多,和c/c++差别比较大,有自动管理内存机制,省心省力。然而,如果写golang真
- 这篇文章主要介绍了Python加密模块的hashlib,hmac模块使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 前言记录CS2000设备使用串口连接以及相关控制。CS2000是一台分光辐射亮度计,也就是可以测量光源的亮度。详细的规格网址参考CS2000
- @property作用:python的@property是python的一种装饰器,是用来修饰方法的。我们可以使用@property装饰器来
- $str = '中华人民共和国123456789abcdefg'; echo preg_match("/^[u4e
- 人生苦短,快学Python!上一周发了一篇文章《Python Tkinter图形工具使用方法及实例解析》,很多小伙伴都希望能多出点教程,今天
- 爬虫数据保存到mongoDB的方法:import pymongo# 首先需要注意,mongodb数据库存储的类型是以键值
- MySQL8数据库安装一、Windows 环境下安装A、下载 MySQL下载地址Select Operating System:Micros
- 本文实例讲述了Python实现新浪博客备份的方法。分享给大家供大家参考,具体如下:Python2.7.2版本实现,推荐在IDE中运行。# -
- 本文实例为大家分享了vue实现下拉菜单树的具体代码,供大家参考,具体内容如下效果:使用 Vue-Treeselect 实现建议通过npm安装
- 一、必备插件🌾Chinese(中文)安装后,按快捷键Ctrl+Shift+P,输入configure languageSettings Sy
- 1 什么是曝光融合曝光融合是一种将使用不同曝光设置拍摄的图像合成为一张看起来像色调映射的高动态范围(HDR)图像的图像的方法。当我们使用相机
- 人们常说人生就是一个不断做选择题的过程:有的人没得选,只有一条路能走;有的人好一点,可以二选一;有些能力好或者家境好的人,可以有更多的选择;