携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
0 环境
- 编辑器:idea或vscode
- 系统版本:windows10
- python版本:3.9.6
1 前言
之前我们用柯里化的方式,完成了在wrap上加装饰器的方式,其实除了我们自己手写的方式外,还可以使用别人给我们准备好的,functools.wraps的作用就是上面的功能,先引入functools,然后在wrap的函数上面添加@functools.wraps(xxxx)的方式即可。柯里化的本质上是让多个参数变成单一参数。
2 应用
只记录函数运行的时间大于n秒时间,比如大于2s,这里的计算时间差的函数total_seconds(),如下代码:和之前的区别点,一个点logger2的入参是具体的值(函数的运行时间是否大于它),你会发现sleep1(时间)还调用了一个time.sleep(xxx),目的是模拟fn函数运行的时间,然后方便下面的判断是否打印。
import datetime
import time
import functools
def logger2(s):
def _logger(fn):
@functools.wraps(fn)
def wrap(*args, **kwargs):
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
end = datetime.datetime.now()
if (end -start).total_seconds() > s:
print("{} called took {}".format(fn.__name__, end - start))
return ret
return wrap
return _logger
@logger2(2)
def sleep1(val):
time.sleep(val)
if __name__ == '__main__':
sleep1(2)
带参的装饰的定义:一个函数,返回值是一个不带参数的装饰器。仔细想想确实是这么一回事,最外面一层就是传具体的参数,作为控制,最终在装饰器内消费掉(逻辑处理完了),并得到结果,也不需要在返回值装饰器带参也是可以理解的。假如我们不在sleep1上添加@logger2(2),是不是就应该这么写了,logger2(2)(sleep1)这样的方式写了。
3 总结
带参装饰器虽然看上去变复杂了,但透过本质看,其实就是外层又套了个函数,它传入了个参数,给我们装饰器使用,换个角度,好处就是在不改变装饰器的情况下,又能灵活控制装饰器的好处,最终引用的变化就是,如上代码:logger2(2)(sleep1)这种,在细化就是logger2(带参的函数)(无参的装饰器函数)。