python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@xxx.setter,@wraps(),@func_name等都是python中的装饰器。
装饰器,装饰的对象是函数或者方法。各种装饰器的作用都是一样的:改变被装饰函数或者方法的功能,性质。
下面主要讲解@wraps(),@func_name,类装饰器这两种装饰器。
目录
一,装饰器的官方定义
二,给某个函数加上一个装饰器
1,一般写法
2,标准的语法糖写法
二,给某个函数加上多个装饰器
2.1 给一个函数添加两个装饰器
2.2 当一个函数具有两个装饰器时的执行顺序
三,带参数装饰器的典型写法
四,@wraps()语法糖(了解)
五,类装饰器
1,不带参数的类装饰器
2,带参数的类装饰器
一,装饰器的官方定义
装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
二,给某个函数加上一个装饰器
1,一般写法
# 为函数添加一个统计运行时长的功能import timedef how_much_time(func):def inner():t_start = time.time()func()t_end = time.time()print("一共花费了{0}秒时间".format(t_end - t_start, ))return inner# 将增加的新功能代码以及被装饰函数运行代码func()一同打包返回,返回的是一个内部函数,这个被返回的函数就是装饰器def sleep_5s():time.sleep(5)print("%d秒结束了" % (5,))def sleep_6s():time.sleep(6)print("%d秒结束了" % (6,))sleep_5s = how_much_time(sleep_5s)# 因为sleep_5s函数的功能就是睡5秒钟,虽然增加了统计运行时间的功能,但是他本身功能没变(还是睡5秒钟),所以仍然用原来函数名接收增加功能了的自己sleep_6s = how_much_time(sleep_6s)t1 = threading.Thread(target=sleep_5s)t2 = threading.Thread(target=sleep_6s)t1.start()t2.start()# 5秒结束了# 一共花费了5.014161109924316秒时间# 6秒结束了# 一共花费了6.011810302734375秒时间
2,标准的语法糖写法
# 为函数添加一个统计运行时长的功能import timeimport threadingdef how_much_time(func):def inner():t_start = time.time()func()t_end = time.time()print("一共花费了{0}秒时间".format(t_end - t_start, ))return inner@how_much_time# @how_much_time等价于sleep_5s = how_much_time(sleep_5s)def sleep_5s():time.sleep(5)print("%d秒结束了" % (5,))@how_much_timedef sleep_6s():time.sleep(6)print("%d秒结束了" % (6,))t1 = threading.Thread(target=sleep_5s)t2 = threading.Thread(target=sleep_6s)t1.start()t2.start()
二,给某个函数加上多个装饰器
在这里以添加两个装饰器为例。
2.1 给一个函数添加两个装饰器
# 为函数添加一个统计运行时长的功能以及日志记录功能import timeimport threadingdef how_much_time(func):print("how_much_time函数开始了")def inner():t_start = time.time()func()t_end = time.time()print("一共花费了{0}秒时间".format(t_end - t_start, ))return innerdef mylog(func):print("mylog函数开始了")def inner_1():print("start")func()print("end")return inner_1@mylog@how_much_time# 等价于mylog(how_much_time(sleep_5s))def sleep_5s():time.sleep(5)print("%d秒结束了" % (5,))if __name__ == '__main__':sleep_5s()#how_much_time函数开始了#mylog函数开始了#start#5秒结束了#一共花费了5.012601613998413秒时间#end
2.2 当一个函数具有两个装饰器时的执行顺序
三,带参数装饰器的典型写法
四,@wraps()语法糖(了解)
因为装饰器实质是就是一个函数,是一个被修饰过函数,他与原来未被修饰的函数是两个不同的函数对象。
所以,这个装饰器丢失了原来函数对象的一些属性,比如:__name__,__doc__等属性。使用wraps语法糖可以保留这些属性。
五,类装饰器
类装饰器这个写法,主要思路就是返回一个增加了新功能的函数对象,只不过这个函数对象是一个类的实例对象。由于装饰器是可调用对象,所以必须在类里面实现__call__方法,这样由类生成的各种实例加上()就可以运行了。
1,不带参数的类装饰器
import timeclass Decorator:def __init__(self, func):self.func = funcdef defer_time(self):time.sleep(5)print("延时结束了")def __call__(self, *args, **kwargs):self.defer_time()self.func()@Decoratordef f1():print("延时之后我才开始执行")f1()
2,带参数的类装饰器
import timeclass Decorator:def __init__(self, func):self.func = funcdef defer_time(self,time_sec):time.sleep(time_sec)print(f"{time_sec}s延时结束了")def __call__(self, time):self.defer_time(time)self.func()@Decoratordef f1():print("延时之后我才开始执行")f1(5)