装饰器
1、默写下面的函数
1 import time 2 def func(): 3 time.sleep(0.2) 4 print("今天放假") 5 def timme(f): # 这里的函数名不能直接用time(),不然会报错,很可能是跟系统函数冲突 6 def inner(): 7 Start_time = time.time() 8 f() 9 End_time = time.time() 10 print(End_time - Start_time) 11 12 return inner 13 func = timme(func) 14 func()
不想修改函数的调用方式,但是还想在原来的函数前后添加功能
timmer就是一个装饰器函数,只是对一个函数有一些装饰作用
timmer就是装饰器函数,timmer()里面的f()就是被装饰函数
2、装饰器的基本原则
原则:开放封闭原则
开放:对扩展是开放的
封闭:对修改是封闭的
3、语法糖
把上面的装饰器用语法糖方式重新定义
1 def timme(f): 2 def inner(): 3 Start_time = time.time() 4 f() 5 End_time = time.time() 6 print(End_time - Start_time) 7 8 return inner 9 10 @timme #语法糖,@装饰器函数名,这句话等价下面的func = timme(func) 11 def func(): #紧挨着的是被装饰函数 12 time.sleep(0.2) 13 print("今天放假") 14 #func = timme(func) #用了语法糖以后,这条代码就被省去了, 15 func()
4、下面被装饰函数func加上返回值以后,当我们调用func()时候有返回值吗
1 def timme(f): 2 def inner(): 3 Start_time = time.time() 4 f() 5 End_time = time.time() 6 print(End_time - Start_time) 7 8 return inner 9 10 @timme #语法糖,@装饰器函数名 11 def func(): #紧挨着的是被装饰函数 12 time.sleep(0.2) 13 print("今天放假") 14 return '过节学习' 15 ret = func() 16 print(ret)
1 0.2000114917755127 2 None
1 def timme(f): 2 def inner(): 3 Start_time = time.time() 4 ret = f() 5 End_time = time.time() 6 print(End_time - Start_time) 7 return ret 8 return inner 9 10 @timme #语法糖,@装饰器函数名 11 def func(): #紧挨着的是被装饰函数 12 time.sleep(0.2) 13 print("今天放假") 14 return '过节学习' 15 ret = func() 16 print(ret)
5、装饰带参数函数的装饰器
带一个参数的装饰器
1 def timme(f): 2 def inner(a): 3 Start_time = time.time() 4 ret = f(a) 5 End_time = time.time() 6 print(End_time - Start_time) 7 return ret 8 return inner 9 10 @timme #语法糖,@装饰器函数名 11 def func(a): #紧挨着的是被装饰函数 12 time.sleep(0.2) 13 print("今天放假",a) 14 return '过节学习' 15 ret = func(2) 16 print(ret)
1 今天放假 2 2 0.2000114917755127 3 过节学习
带两个参数的装饰器
1 def timme(f): 2 def inner(*args): 3 Start_time = time.time() 4 ret = f(*args) # 这里还需要用*把多个参数打散传入 5 End_time = time.time() 6 print(End_time - Start_time) 7 return ret 8 9 return inner 10 11 @timme # 语法糖,@装饰器函数名 12 def func2(a): # 紧挨着的是被装饰函数 13 time.sleep(0.2) 14 print("今天放假", a) 15 return '过节学习' 16 17 18 @timme # 语法糖,@装饰器函数名 19 def func3(a, b): # 紧挨着的是被装饰函数 20 time.sleep(0.2) 21 print("今天放假", a, b) 22 return '过节学习' 23 24 25 ret2 = func2(2) 26 print(ret2) 27 ret3 = func3(3, 4) 28 print(ret3)
1 今天放假 2 2 0.2000114917755127 3 过节学习 4 今天放假 3 4 5 0.2000114917755127 6 过节学习
6、包含关键字的装饰器
1 def timme(f): 2 def inner(*args,**kwargs): 3 Start_time = time.time() 4 ret = f(*args,**kwargs) # 这里还需要用*把多个参数打散传入 5 End_time = time.time() 6 print(End_time - Start_time) 7 return ret 8 9 return inner 10 11 12 @timme # 语法糖,@装饰器函数名 13 def func2(a,b): # 紧挨着的是被装饰函数 14 time.sleep(0.2) 15 print("今天放假", a,b) 16 return '过节学习' 17 18 19 ret = func2(4,6) 20 print(ret) 21 ret2 = func2(2,b = 9) 22 print(ret2)
1 今天放假 4 6 2 0.2000114917755127 3 过节学习 4 今天放假 2 9 5 0.2000112533569336 6 过节学习
7、装饰器的固定格式
1 def wrapper(f): #装饰函数,f是被装饰函数 2 def inner(*args,**kwargs): 3 '''在被装饰函数之前要做的事情''' 4 ret = f(*args,**kwargs) #被装饰函数 5 '''在被装饰函数之后要做的事情''' 6 return ret 7 return inner 8 9 @wrapper #语法糖,@装饰器函数名,等价于func = wrapper(func) 10 def func(a,b): #被装饰函数 11 time.sleep(0.5) 12 print("放假最后一天了",a,b ) 13 return '假期是充实的' 14 15 ret = func(b = 9,a = 3) #实际执行的是inner函数 16 print(ret)
1 放假最后一天了 3 9 2 假期是充实的
8、装饰器的聚合与打散
传参:聚合,就是说传参的时候是把几个参数一起传给函数
调用:打散,就是说具体调用的时候是一个一个参数来使用,那么好比打散来用
1 def wrapper(func): 2 def inner(*args,**kwargs): 3 print("在被装饰之前做的事情") 4 ret = func(*args,**kwargs) 5 print("被装饰之后做的事情") 6 return ret 7 return inner 8 9 @wrapper 10 def func(day): 11 print("节后第%s天"%day) 12 13 return "继续加油干" 14 15 ret = func(1) 16 print(ret)
上面代码结果是:
1 在被装饰之前做的事情 2 节后第1天 3 被装饰之后做的事情 4 继续加油干
9、带参数的装饰器
一个装饰器一般就三层,最外一层是带参数,方便用参数的设置来决定是否进行装饰,这样避免挨个挨个进行去掉装饰
1 import time 2 Flag = False 3 def timmer_out(Flag): 4 def timmer(func): 5 def inner(*args,**kwargs): 6 if Flag: 7 start_time = time.time() 8 ret = func(*args,**kwargs) 9 end_time = time.time() 10 print(end_time - start_time) 11 return ret 12 else: 13 ret = func(*args, **kwargs) 14 return ret 15 return inner 16 return timmer 17 #timmer = timmer_out(Flag),timmer_out后面带括号就是函数调用 18 @timmer_out(Flag) 19 def get(): 20 time.sleep(0.2) 21 print("快上班了") 22 23 get()
1 快上班了
10、装饰器进阶:多个装饰器同时装饰同一个函数
1 def wrapper1(func): 2 def inner1(*args,**kwargs): 3 print("wrapper1开始装饰") 4 ret = func(*args,**kwargs) 5 print("wrapper1装饰结束") 6 return ret 7 return inner1 8 9 def wrapper2(func): 10 def inner2(*args,**kwargs): 11 print("wrapper2开始装饰") 12 ret = func(*args,**kwargs) 13 print("wrapper2装饰结束") 14 return ret 15 return inner2 16 17 def wrapper3(func): 18 def inner3(*args,**kwargs): 19 print("wrapper3开始装饰") 20 ret = func(*args,**kwargs) 21 print("wrapper3装饰结束") 22 return ret 23 return inner3 24 25 @wrapper3 26 @wrapper2 27 @wrapper1 28 def f(a): 29 print("输入的数是:",a) 30 return "返回结束" 31 32 print(f(666))
1 wrapper3开始装饰 2 wrapper2开始装饰 3 wrapper1开始装饰 4 输入的数是: 666 5 wrapper1装饰结束 6 wrapper2装饰结束 7 wrapper3装饰结束 8 返回结束
多个装饰器同时装饰同一个函数的执行顺序: