从一个小例子来了解装饰器,现要统计一个函数执行耗时:
原始版本
import time
# time模块有提供时间相关函数
def do_something():
print("do_something")
time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时
start = time.time()
do_something()
print(time.time() - start)
#result:
# do_something
# 0.5000283718109131
问题:上述代码可以完成这个功能,但之后会发现,如果我们要统计其它函数,就必须在每个函数前后加入相应代码。
装饰器版本 1(无参数)
import time
def execute_time(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner
# time模块有提供时间相关函数
def do_something():
print("do_something")
time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时
do_something = execute_time(do_something)
do_something()
#result:
# do_something
# 0.5000283718109131
从上述代码可以看到,使用了另一个函数 execute_time
给我们要统计耗时的函数进行了包装。此时,这个 execute_time
函数就叫做装饰器函数,而我们要统计的那个函数也就是 do_something
函数就是被装饰的函数。
问题:函数执行的时候实际上是调用的 execute_time
函数中的 inner
函数,这种方法虽然解决了原始版本的问题,但是当我们要统计的函数拥有返回值的时候,这时候我们获取不到返回值。
装饰器版本 2(有固定参数)
import time
def execute_time(func):
def inner(do):
start = time.time()
result = func(do)
print(time.time() - start)
return result
return inner
# time模块有提供时间相关函数
def do_something(do):
print("do_something", do)
time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时
return 'do_something over'
do_something = execute_time(do_something)
print(do_something('say hello'))
# result:
# do_something say hello
# 0.5000283718109131
# do_something over
为了解决装饰器版本 1 的问题,我在 inner
函数里面加了个返回值。
问题:当被装饰函数的参数个数与 inner
参数个数不同时,这个装饰器就不适用了。
装饰器版本 3(动态参数)
import time
def execute_time(func):
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(time.time() - start)
return result
return inner
# time模块有提供时间相关函数
def do_something(do1,do2):
print("do_something", do1,do2)
time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时
return 'do_something over'
do_something = execute_time(do_something)
print(do_something('say hello1','say hello2'))
# result:
# do_something say hello1 say hello2
# 0.5000283718109131
# do_something over
在之前有个动态参数的知识点,正好可以解决上一步的问题。
终极版本(语法糖 @)
import time
def execute_time(func):
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(time.time() - start)
return result
return inner
@execute_time
def do_something(do1,do2):
print("do_something", do1,do2)
time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时
return 'do_something over'
# do_something = execute_time(do_something)
print(do_something('say hello1','say hello2'))
# result:
# do_something say hello1 say hello2
# 0.5000283718109131
# do_something over
对于装饰器,python 内部给我们提供了语法糖支持。在需要被装饰的函数名上部使用 @装饰器函数名称
即可。
评论区