python笔记 带参装饰器中

80 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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)

image.png

带参的装饰的定义:一个函数,返回值是一个不带参数的装饰器。仔细想想确实是这么一回事,最外面一层就是传具体的参数,作为控制,最终在装饰器内消费掉(逻辑处理完了),并得到结果,也不需要在返回值装饰器带参也是可以理解的。假如我们不在sleep1上添加@logger2(2),是不是就应该这么写了,logger2(2)(sleep1)这样的方式写了。

3 总结

带参装饰器虽然看上去变复杂了,但透过本质看,其实就是外层又套了个函数,它传入了个参数,给我们装饰器使用,换个角度,好处就是在不改变装饰器的情况下,又能灵活控制装饰器的好处,最终引用的变化就是,如上代码:logger2(2)(sleep1)这种,在细化就是logger2(带参的函数)(无参的装饰器函数)。