提问人:Gustavo Nunes 提问时间:9/25/2023 最后编辑:Gustavo Nunes 更新时间:9/26/2023 访问量:47
带有接收参数的函数的 Python 装饰器
Python decorator with a function that receives a parameter
问:
Decorator 未按预期工作
我试图更多地了解装饰器,所以我搜索并得到了许多视频,这些视频使这个确切的功能:
def tictoc(func):
def wrapper():
t1 = time.time()
return func()
t2 = time.time()-t1
print(f'Took {t2} seconds to run.')
return wrapper
所以我做了一个阶乘函数,它接受一个参数(你想看到的阶乘数字)
@tictoc
def fat(num):
f = 1
for x in range(1, num+1):
f *= x
return f
print(fat(5))
然后我运行了它
但是我收到此错误:TypeError:tictoc..wrapper() 接受 0 个位置参数,但给出了 1 个
有人可以解释一下我做错了什么吗?
答:
0赞
Domenico Spidy Tamburro
9/25/2023
#1
正如 JonSG 所指出的,return 语句会跳过它之后的其余代码,因此永远不会计算 t2,也不会执行打印。
您可能希望重写代码,如下所示:
import time
def tictoc(func):
def wrapper(*args, **kwargs):
t1 = time.time()
_func = func(*args, **kwargs)
t2 = time.time()-t1
print(f'Took {t2} seconds to run.')
return _func
return wrapper
@tictoc
def fac(num):
f = 1
for x in range(1, num+1):
f *= x
return f
print(fac(3))
首先,您需要将参数传递给装饰器。您可以通过在内部包装函数中使用 和 来做到这一点(也许这里是多余的)。然后,内部包装器将这些传递给包装函数。其次,将函数的结果存储到函数中,并在计算 t2 后返回。*args
**kwargs
**kwargs
_func
0赞
Prayson W. Daniel
9/25/2023
#2
问题#1:装饰器不允许传递参数,因为您在没有参数的情况下调用函数
def tictoc(func):
def wrapper():
t1 = time.time()
return func() #<—- here is the 🐛
t2 = time.time()-t1
print(f'Took {t2} seconds to run.')
return wrapper
我们可以纠正:
def tictoc(func):
def wrapper(*args, **kwargs):
t1 = time.time()
return func(*args, **kwargs)
t2 = time.time()-t1 # <— this will not be evaluated as we have returned
print(f'Took {t2} seconds to run.') # <- this too
return wrapper
问题#2:Return语句将返回。T2 和上面评论中指出的打印将不被评估。我们可以解决这个问题:
def tictoc(func):
def wrapper(*args, **kwargs):
t1 = time.time()
results = func(*args, **kwargs)
t2 = time.time()-t1
print(f'Took {t2} seconds to run.')
return results
return wrapper
这现在应该可以工作了。我们可以添加最后一个调整来保留函数的名称
事实上,装饰器将更改函数的名称。
@tictoc
def fat(num):
f = 1
for x in range(1, num+1):
f *= x
return f
print(fat.__name__)
#outputs wrapper
要解决此问题,请执行此操作
from functools import wraps
def tictoc(func):
@wraps(func)
def wrapper(*args, **kwargs):
t1 = time.time()
results = func(*args, **kwargs)
t2 = time.time()-t1
print(f'Took {t2} seconds to run.')
return results
return wrapper
的输出不正确。print(fat.__name__)
fat
编写装饰器的另一种方法是使用更易于阅读的类。
class tictoc:
def __init__(self, func):
self.func = func
self.__name__ = func.__name__
def __call__(self, *args, **kwargs):
t1 = time.time()
results = self.func(*args, **kwargs)
t2 = time.time() - t1
print(f'Took {t2} seconds to run.')
return results
这应该如上所述,但自由度较小。例如,向装饰器添加参数。有了函数,我们就可以用三个嵌套函数来做到这一点
def tictoc(loops=1):
def inner(func):
@wraps(func)
def wrapper(*args, **kwargs):
t2_ = 0
for loop in range(1, loops+1):
print(f'{loop=}')
t1 = time.time()
results = func(*args, **kwargs)
t2 = time.time() - t1
t2_ += t2
print(f'Took {t2} seconds to run')
if loops > 1:
print(f'Took average {t2_/loops} seconds to run')
return results
return wrapper
return inner
@tictoc(3)
def fat(num):
f = 1
for x in range(1, num + 1):
f *= x
return f
print(fat(5))
还在琢磨如何用课堂;)
评论
1赞
Domenico Spidy Tamburro
9/25/2023
最初,您的答案看起来与我之前发布的答案相同。最终,您正在添加非常有趣的材料。荣誉。
0赞
Prayson W. Daniel
9/26/2023
我没有看到你的:(相反,我会编辑你的。
评论
return func()