当前位置: 首页 > 科技观察

@wraps装饰器:让你的Python代码更短小可爱-一个简单的例子就知道了

时间:2023-03-14 11:34:07 科技观察

我们在上一篇文章(Python例子理解并发和并行)中使用了@timer。在定义函数时,添加一个小的@timer,这样函数执行后,会自动在控制台报告其运行时间。比如下面的:@timerdefpiper():foriinrange(10000):i=i*i**10piper()output:timer:using0.00600s其实这个定时器逻辑@timer是我们自己在Python中的装饰器特性[1]实现。拆解逻辑其实我们不需要装饰器,我们可以自己实现时序逻辑。defpiper():foriinrange(10000):i=i*i**10t=time.time()#记录函数开始时间piper()print(f"timer:using{time.time()-t:.5f}s")#获取函数的运行时间并打印出来注意我们在执行函数的时候,逻辑是上下包裹的。如果我们想让函数有自己的时序逻辑,那么为了覆盖原来的函数,只能定义一个新的函数。deftime_wrapper(func):#func是一个函数t=time.time()func()print(f"timer:using{time.time()-t:.5f}s")time_wrapper(piper)output:timer:using0.00600s当我们要测试某个函数的运行时间时,只要将函数名输入time_wrapper即可。更优雅的改进上面的代码显然有缺点:我们在编程时,精神负担增加;此外,代码更加冗长。如果我们只是想在函数中增加一个新的函数,显然不能使用time_wrapper,因为它不会改变piper所以请来今天的主角修饰符@wraps[2]。同样以我们的定时器为例,我们让@timer下的所有函数都这样处理:deftimer(func):@wraps(func)definner_func():t=time.time()rts=func()print(f"timer:using{time.time()-t:.5f}s")returnrtsreturninner_func以piper为例,我们经历了如下变化。@timerdeforiginalpiper():foriinrange(10000):i=i*i**10其实你再调用piper的时候,你的piper内部逻辑已经变了:defcurrentpiper():t=time.time()rts=原始piper()print(f"timer:using{time.time()-t:.5f}s")returnrts总结本文简单,读者朋友“科普一下”装饰器,注意我们是其实这里上面只修改了没有参数的函数。其实装饰器还有很多更优雅的用法,比如传入参数*args,**kwargs,修饰__call__等用法。期待未来能遇到好的应用场景,与朋友分享我的经验。