日期:2020年3月2日
作者:Commas
注释:学习就是为了忘记,接上一章《Python3之装饰器(Decorator)浅谈》,现在讲一下Python装饰器进阶;
如果您想了解更多有关Python的知识,那么请点《我的Python浅谈系列目录》
书接上文,我们现在来看看装饰带参数函数的装饰器,如下:
import time
def calculate_time(f):
"""装饰器函数"""
# (1)采用*args, **kwargs来接收参数
# def wrapper():
def wrapper(*args, **kwargs):
"""这是wrapper函数的说明文档"""
start_time = time.time()
# (2)被装饰函数f接受*args, **kwargs参数
# f()
f(*args, **kwargs)
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
return wrapper
@calculate_time
def func(param):
"""这是func函数的说明文档"""
time.sleep(1)
print("执行了{}()函数,其中param={}".format(func.__name__, param))
func(1)
# =======控制台输出结果=======
执行了wrapper()函数,其中param=1
<function func at 0x000001F6E2F698C8>的执行时间:1.0006613731384277
如果被装饰的函数有返回值,那么就应该修改为:
def calculate_time(f):
"""装饰器函数"""
def wrapper(*args, **kwargs):
"""这是wrapper函数的说明文档"""
start_time = time.time()
# (2)接收返回值
# f(*args, **kwargs)
ret = f(*args, **kwargs)
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
# (3)返回返回值
return ret
return wrapper
@calculate_time
def func(param):
"""这是func函数的说明文档"""
time.sleep(1)
# (1)被装饰的函数有返回值
# print("执行了{}()函数,其中param={}".format(func.__name__, param))
return "执行了{}()函数,其中param={}".format(func.__name__, param)
# func(1)
ret = func(1)
print(ret)
# =======控制台输出结果=======
<function func at 0x0000019F789698C8>的执行时间:1.0038354396820068
执行了wrapper()函数,其中param=1
无论是装饰带参数函数的装饰器,还是装饰有返回值函数的装饰器,都有一个不完美的地方,那就是被装饰后的函数,函数的内置属性(如__name__)都发生了变化。如果想保证被装饰的函数做到“不变”,那么我们要不自己遍历,将对应的值更新,要么可以借助@wraps
,如下:
import time
# (1)从模块functools导入wraps
from functools import wraps
def calculate_time(f):
"""装饰器函数"""
# (2)使用wraps
@wraps(f)
def wrapper(*args, **kwargs):
"""这是wrapper函数的说明文档"""
start_time = time.time()
ret = f(*args, **kwargs)
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
return ret
return wrapper
@calculate_time
def func(param):
"""这是func函数的说明文档"""
time.sleep(1)
return "执行了{}()函数,其中param={}".format(func.__name__, param)
# func(1)
ret = func(1)
print(ret)
# =======控制台输出结果=======
<function func at 0x0000020C3DAC0048>的执行时间:1.0006630420684814
执行了func()函数,其中param=1
结果完美,一切OK!
但是@wraps(f)
是个什么梗,还可以给装饰器传参,且待我慢慢说来,这个实际是分两部分执行,如下:
那么我们来实现一个类似的吧,@calculate_time(True)
,用来控制是否计算函数执行时间,如下:
import time
from functools import wraps
def calculate_time(flag):
def inner(f):
"""装饰器函数"""
@wraps(f)
def wrapper(*args, **kwargs):
"""这是wrapper函数的说明文档"""
if flag:
start_time = time.time()
ret = f(*args, **kwargs)
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
else:
ret = f(*args, **kwargs)
return ret
return wrapper
return inner
@calculate_time(True)
def func(param):
"""这是func函数的说明文档"""
time.sleep(1)
return "执行了{}()函数,其中param={}".format(func.__name__, param)
ret = func(1)
print(ret)
# =======控制台输出结果=======
<function func at 0x00000162250300D0>的执行时间:1.0001797676086426
执行了func()函数,其中param=1
@装饰器A
@装饰器B
def 被装饰函数():
pass
从图和代码可以知,函数的执行过程是:
1(装饰器A)→2(装饰器B)→3(装饰器B)→4(装饰器A)
版权声明:本文为博主原创文章,如需转载,请给出:
原文链接:https://blog.csdn.net/qq_35844043/article/details/104609540