python进阶——装饰器系列之通过绩效奖金趣说装饰器原理

花间影清欢课程 2024-03-28 01:45:11
一、楔子作为一个会写函数的python开发,我们从今天开始要去公司上班了。写了一个函数,就交给其他开发者使用了。 def func1(): print('in func1')季度末,公司的领导要给大家发绩效奖金了,就提议对这段日子所有人开发的成果进行审核,审核的标准是什么呢?就是统计每个函数的执行时间。 领导把这个任务交给你来做了,这时候你要怎么办呢?你一想这好办,把函数改一下就好了: import timedef func1(): start = time.time() print('in func1') print(time.time() - start)func1()但是公司如果有万千上百个函数接口,挨个这样改一遍1个礼拜过去了,等领导审核完,再挨个给删了。。。又1个礼拜过去了。。。这是不是很闹心? 你觉得不行,不能让自己费劲儿,告诉所有开发者,现在你们都在自己原本的代码上加上一句计算时间的语句 import timedef func1(): print('in func1')start = time.time()func1()print(time.time() - start)这样估计其他开发者会心中已经在划小圈圈诅咒你了。因此你又灵机一动,写了一个timer函数 import timedef timer(func): start = time.time() func() print(time.time() - start)def func1(): print('in func1')def func2(): print('in func2')timer(func1)timer(func2)这样看起来是不是简单多啦?不管写了多少个函数都可以调用这个计时函数来计算函数的执行时间了。尽管现在修改成本已经变得很小很小了,但是对于同事来说还是改变了这个函数的调用方式,假如某同事因为相信你,在他的代码里用你的方法用了2w多次,那他修改完代码你们友谊的小船也就彻底地翻了。 你要做的就是,让你的同事依然调用func1,但是能实现调用timer方法的效果。 import timedef timer(func): start = time.time() func() print(time.time() - start)def func1(): print('in func1')func1 =timer #要是能这样的就完美了。。。可惜报错func1()非常可惜,上面这段代码是会报错的,因为timer方法需要传递一个func参数,我们不能在赋值的时候传参,因为只要执行func1 = timer(func1),timer方法就直接执行了,下面的那句func1根本就没有意义。到了这里,我们的思路好像陷入了僵局。 此时,我们的装饰器就闪亮登场了。 二、装饰器的形成过程2.1 初代装饰器import timedef func1(): print('in func1')def timer(func): def inner(): start = time.time() func() print(time.time() - start) return innerfunc1 = timer(func1)func1()忙活了这么半天,终于初具规模了!现在已经基本上完美了,唯一碍眼的那句话就是还要再做一次赋值调用。 2.2 二代装饰器你觉得碍眼,python的开发者也觉得碍眼,所以就为我们提供了一句语法糖来解决这个问题! import timedef timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner@timer #==> func1 = timer(func1)def func1(): print('in func1')func1()到这里,我们可以简单地总结一下:   装饰器的本质:一个闭包函数   装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展 2.3 三代装饰器还有最后一个问题要解决,刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢? def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner@timerdef func1(a): print(a)func1(1)其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢? import timedef timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner@timer #==> func1 = timer(func1)def func1(a,b): print('in func1')@timer #==> func2 = timer(func2)def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over'func1('aaaaaa','bbbbbb')print(func2('aaaaaa'))装饰器——成功hold住所有函数传参现在参数的问题已经完美地解决了,可是如果你的函数是有返回值的呢? import timedef timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner@timer #==> func2 = timer(func2)def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over'func2('aaaaaa')print(func2('aaaaaa'))装饰器——带返回值的装饰器2.4 究级装饰器刚刚那个装饰器已经非常完美了,但是正常情况下查看函数的一些信息的方法在此处都会失效。 def index(): '''这是一个主页信息''' print('from index')print(index.__doc__) #查看函数注释的方法print(index.__name__) #查看函数名的方法为了不让他们失效,我们还要在装饰器上加上一点来完善它: from functools import wrapsdef deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper@decodef index(): '''哈哈哈哈''' print('from index')print(index.__doc__)print(index.__name__)装饰器——wraps demo总结至此,我们不只演化出究级装饰器,而且可以轻易地在不改变同事代码结构的情况下完成了领导的任务。皆大欢喜,开心的领绩效奖金吧。
0 阅读:0