Python编写装饰器,给任意函数计时

蚂蚁学Python

共 1767字,需浏览 4分钟

 ·

2021-05-21 23:03

在开发代码时,经常有这样的需求,想知道调用一个函数的入参、返回值、花费时间。


对应这个调用,我们可以自己在函数开头打印参数、末尾打印结果、结尾时间减去开始时间计时。


然而这样的代码,其实任何函数都一样,有没有办法写一次代码多次调用呢。


这其实就是“给任何函数,增加一个公共的附加特性”,可以用Python的解释器解决。


# 1、导入相关的包


import functoolsimport loggingimport time
log_format = "%(asctime)s %(message)s"logging.basicConfig(format=log_format, level=logging.INFO)


这用到了functools包,它有wraps方法,是装饰需要的函数。


# 2、编写装饰器


def time_logger(func):  @functools.wraps(func)  def wrapper_timer(*args, **kwargs):    logging.info(f"BeginFunction {func.__name__!r}, args={args}, kwargs={kwargs}")    start_time = time.perf_counter()  # 1    value = func(*args, **kwargs)    end_time = time.perf_counter()  # 2    run_time = end_time - start_time  # 3    logging.info(f"EndFunction {func.__name__!r} in {run_time:.4f} secs")    return value
return wrapper_timer


大家注意,这个装饰器会被任何函数使用。其中的func(*args, **kwargs)中的func就是目标函数,args、kwargs是这个函数调用的参数。


这就实现了一个装饰器。


# 3、使用装饰器给函数计时


@time_loggerdef my_func(name, age):  logging.info(f"my func begin, {name}, {age}")  time.sleep(2)  logging.info(f"my func end, {name}, {age}")


@time_logger就是计时器的装饰器使用方式,任何函数只需要这个简单地一行代码,就可以加上这个功能。


# 4、我们来看看调用效果


执行如下代码:

my_func("antpython", "99")


打印结果为:

2021-05-17 20:30:26,294 BeginFunction 'my_func', args=('antpython', '99'), kwargs={}2021-05-17 20:30:26,294 my func begin, antpython, 992021-05-17 20:30:28,295 my func end, antpython, 992021-05-17 20:30:28,295 EndFunction 'my_func' in 2.0007 secs


其中第一行BeginFunction、最后一行EndFunction,都是装饰器里面的输出。


而my func begin、my func end,则是自己的函数的输出。


# 5、最后的总结


对于装饰器,可以有很多用途:

  • WEB服务中检测用户是否登录

  • 加入所有函数的日志、计时功能

  • 对所有访问数据库的函数加上入侵检测功能

  • 对用户的访问请求做攻击检测

  • 自动处理数据库的链接提取、提交、回滚等操作


只要是一个通用的功能,都可以用装饰器来解决。这在其他语言比如JAVA中也叫做拦截器、代理等功能。


这是一个很有用的特性,赶快试试吧!

浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报