Python3之装饰器
参考:https://www.cnblogs.com/songyue/p/5196809.html
例如以前写了一个简单的函数sum1如下
1 2 3 4 5 6 7 | def sum1(): sum = 1 + 2 print ( sum ) sum1() print ( '函数名为' ,sum1.__name__) |
运行结果为
1 2 | 3 函数名为 sum1 |
假如需要新加一个功能查看该函数运行执行了多长时间,可以导入时间模块记录开始时间及结束时间,用结束时间减开始时间及可得到运行时间,修改函数如下
1 2 3 4 5 6 7 8 9 10 11 12 | import time import functools def sum1(): start = time.time() sum = 1 + 2 print ( sum ) end = time.time() print ( "Time used:" ,end - start) sum1() print ( '函数名为' ,sum1.__name__) |
运行结果
1 2 3 | 3 Time used: 2.6464462280273438e - 05 函数名为 sum1 |
可是还是许多函数需要增加运行时间的功能,难道一个个函数去改嘛,可以定义一个时间函数timeit将sum1作为参数传递给时间函数timeit在timeit里面调用sum1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import time import functools def sum1(): sum = 1 + 2 print ( sum ) def timeit(func): start = time.time() func() end = time.time() print ( 'Time used:' ,end - start) timeit(sum1) |
运行结果
1 2 | 3 Time used: 2.574920654296875e - 05 |
可以运行,但是还是修改了一部分代码,把sum1()改成了timeit(sum1),直接运行sum1()还是不会打印运行时间,如果sum在N处被调用了,不得不去修改N处代码。所以需要将sum1()具有和timeit(sum1)一样的效果,于是将timeit赋值给sum1,可是timeit是有参数的,所以需要找个方法去统一参数,将timeit(sum1)发返回值(计算运行时间的函数)赋值给sum1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import time import functools def sum1(): sum = 1 + 2 print ( sum ) def timeit(func): def test(): start = time.time() func() end = time.time() print ( 'Time used:' ,end - start) return test sum1 = timeit(sum1) #sum1为函数名需要加括号执行执行 sum1() print ( '函数名为' ,sum1.__name__) |
执行结果
1 2 3 | 3 Time used: 3.0279159545898438e - 05 函数名为 test |
一个装饰器就做好了,我们只需要在定义sum1之后调用sum1之前,加上sum1=timeit(sum1),就可以达到计时的目的,这就是装饰器的概念,看起来像是sum1倍timeit装饰了,Python提供一个语法糖来降低字符输入量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import time import functools def timeit(func): def test(): start = time.time() func() end = time.time() print ( 'Time used:' ,end - start) return test @timeit def sum1(): sum = 1 + 2 print ( sum ) #sum1为函数名需要加括号执行执行 sum1() print ( '函数名为' ,sum1.__name__) |
PS:这里的@timeit等价于sum1=timeit(sum1)
执行结果
1 2 3 | 3 Time used: 2.8848648071289062e - 05 函数名为 test |
我们可以看到执行的函数名为test,因为返回的是test函数,需要把原始函数sum1的__name__属性复制到test()函数中,否则,有些依赖函数前面的代码执行就会出错,不需要编写test.__name__=func.__name__这样的代码,python内置的functools.wraps就是干这个事的,所以,一个完整的装饰器写法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import time import functools def timeit(func): @functools .wraps(func) def test(): start = time.time() func() end = time.time() print ( 'Time used:' ,end - start) return test @timeit def sum1(): sum = 1 + 2 print ( sum ) #sum1为函数名需要加括号执行执行 sum1() print ( '函数名为' ,sum1.__name__) |
执行结果
1 2 3 | 3 Time used: 3.647804260253906e - 05 函数名为 sum1 |
函数名为原始函数名sum1
以上装饰器装饰函数为不带参数函数,假如需要装饰多个函数而有的函数带参数有的函数不带参数则需要编写一个通用装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import time import functools def timeit(func): @functools .wraps(func) def test( * args, * * kw): start = time.time() func( * args, * * kw) end = time.time() print ( 'Time used:' ,end - start) #return func(*args,**kw) return test @timeit def sum1(s): print (s) sum1( 'hello world' ) print ( '函数名为' ,sum1.__name__) |
test()
函数的参数定义是(*args, **kw)
,因此,test()
函数可以接受任意参数的调用。在test()
函数内在运行函数的前后加时间记录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!