装饰器函数
三元运算符乱入
''' 变量 = 条件返回True的结果 if 条件 else 条件返回false的结果 ''' a,b = 1,2 c = b if a>b else a print(c)
装饰器
你参与的项目上线了,你写了一批函数,类似下边 (虽然很low but。。。)
def fun(): print('jcc is a beauty')
新的需求来了,需要测试你的函数运行时间,你很快写好了。
import time def fun(): start = time.time() print('jcc is a beauty') end = time.time() return end-start
代码提交给你的leader,你被骂了,写的什么垃圾代码,去好好看看开闭原则,于是你又去苦逼的改代码,最终在你使劲全身力气之后,写出了如下代码,
你没有改变源函数,而是扩展了一个新的函数
import time def fun(): print('jcc is a beauty') #扩展函数 def timer(): start = time.time() fun() end = time.time() return end - start print(timer())
但是你还有n个类似的代码,难道每一个都要再为之单独写一个timer函数?
这显然不符合高级程序员的作风,于是,你又改了你的代码,这样你就可以只扩展一个timer
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time def fun(): print('jcc is a beauty') def fun1(): print('jcc is so beautiful') #扩展函数 def timer(f): start = time.time() f() end = time.time() return end - start print(timer(fun)) print(timer(fun1))
为了避免再次被leader黑一脸,你把代码拿给同事看,你期待得到同时的夸奖,
but,你还是被同事黑了一脸,你的函数被很多兄弟们调用,你难道skr大猪蹄子?让兄弟们把调用方式都修改一遍?
虽然你心里想 come on man,that is not my business(此处忽略我的语法错误,如果有的话。。),但是 你不得不重新
修改你的代码,让你的兄弟们满意,苦思冥想 终于 灵光一闪,你写出了如下代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time def fun(): print('jcc is a beauty') #扩展函数 def timer(f): start = time.time() f() end = time.time() return end - start fun = timer #你把timer函数的地址赋值给fun,你只需要调用fun()就可以实现对timer的调用 fun(f) #but 你忽略了timer函数需要传参,而现在fun已经不再指向原来的fun函数,你无法为之传参
于是,你又又又修改了你的代码。。。既然不能传参,那我返回一个不需要传参的函数不就ok了?你奋笔疾书写下了如下代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time def fun(): print('jcc is a beauty') #扩展函数 def timer(f): def inner(): start = time.time() f() end = time.time() return end - start return inner fun = timer(fun) fun()#你的兄弟们只需要按照以前的调用方式即可
此处的timer就是一个装饰器(不改变调用方式,在原有的基础上加功能),fun函数就是一个被装饰函数
语法糖???
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time def timer(f): def inner(): start = time.time() f() end = time.time() return end - start return inner # fun = timer(fun) 只要在被装饰器上边加上@装饰器名字 就可以省略这句话 @timer def fun(): print('jcc is a beauty') fun()
过了一段时间,随着你的技术不断提高,leader给你分配了一些稍微复杂的模块,
你的函数第一次有了参数(嗯?第一次?!),还有了返回值!!! 为了适应新加入的函数,你必须要修改你的装饰器了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time #装饰器timer def timer(f): def inner(*args): start = time.time() res = f(*args) #在此接受被装饰函数的返回值 end = time.time() return res #在此把被装饰函数的返回值返回 return inner #被装饰函数fun @timer def fun(*args): return sum(args)#没错,你写的模块就是求一系列数值和,,,并返回 # fun = timer(fun) res = fun(1,2,3)#调用函数,接受返回值
费了老大劲的你解决了所有问题,现在的你以为你可以走遍天下了
于是你总结了装饰器的固定模式
def wapper(fun): def inner(*args,**kwargs):#*args,**kwargs 定义是元组,调用是被打散 #调用函数前要做的事情 res = fun(*args,**kwargs) #调用函数 #调用函数后要做的事情 return res return inner
过了两天,leader说可以撤掉测试时间的代码了 ,于是你费了一上午的时间在你所有的函数上面注释掉对装饰器的调
用,长舒一口气去找leader,结果他说想在测试一下,你内心mmp,脸上不得不笑嘻嘻,难道每次都要手动操作装饰器的执行?
如果有简单的方式就好了,你深思熟虑终于想到了一个主意
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time FLAG = False #定义一个开关,True时执行装饰器中添加的代码,false只执行被装饰的函数,需要传入装饰器中,but, # 装饰器有一个参数是被装饰函数,,, #装饰器timer def out_timer(flag): def timer(f): def inner(*args): if flag: start = time.time() res = f(*args) end = time.time() print(end-start) return res else: res = f(*args) return res return inner return timer #被装饰函数fun @out_timer(FLAG) #--->在此传入开关变量 相当与先执行了out_timer(FLAG)函数,之后返回timer 然后加上@ def fun(*args): return sum(args) print(fun(1,2,3)) 问题解决,可以很方便的设置是否使用装饰器
多个装饰器装饰同一个函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#装饰器1 def waper1(f): def inner1(): print('waper1---before') f() print('waper1---after') return inner1 #装饰器2 def waper2(f): def inner2(): print('waper2---before') f() print('waper2---after') return inner2 @waper1 @waper2 def fun(): print(1) fun()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#执行结果 ''' waper1---before waper2---before 1 waper2---after waper1---after '''