我正在尝试学习如何在Python中使用装饰器,但这是一项艰巨的任务。我制作了一个装饰器,该装饰器应执行指定次数的装饰函数。我设法产生执行此任务的代码:
def repeat(num_times):
def decorator_repeat(func):
def wrapper_repeat(x):
for _ in range(num_times):
func(x)
return wrapper_repeat
return decorator_repeat
@repeat(4)
def helloWorld(say):
print(say)
helloWorld("Hey everyone!")
然后,我试图再次再现此代码,但是这次我使用了while循环而不是for循环,如下所示:
def repeat(num_times):
def decorator_repeat(func):
def wrapper_repeat(x):
while num_times > 0:
func(x)
num_times -= 1
return wrapper_repeat
return decorator_repeat
@repeat(4)
def helloWorld(say):
print(say)
helloWorld("Hey everyone!")
但是现在函数返回错误。
Traceback (most recent call last):
File "untitled.py", line 118, in <module>
helloWorld("Hey everyone!")
File "untitled.py", line 108, in wrapper_repeat
while num_times > 0:
UnboundLocalError: local variable 'num_times' referenced before assignment
对我来说,这些功能应该完全相同,但事实并非如此。您可以帮助我了解我的代码有什么问题吗?
谢谢!
区别在于,带有while
的版本分配了num_times
变量。这默认使它对wrapper_repeat()
函数是本地的,因此它与num_times
中的repeat()
变量不同。您需要将其声明为非本地:
def repeat(num_times):
def decorator_repeat(func):
def wrapper_repeat(x):
nonlocal num_times
while num_times > 0:
func(x)
num_times -= 1
return wrapper_repeat
return decorator_repeat
请注意,此定义还有另一个问题。由于您正在修改捕获的闭包变量,因此该值将在对装饰函数的调用之间保持不变。因此,如果您第二次调用helloWorld
,则不会重复,因为不满足while
条件。
更好的定义将num_times
复制到一个临时变量。这解决了两个问题。
def repeat(num_times):
def decorator_repeat(func):
def wrapper_repeat(x):
num = num_times
while num > 0:
func(x)
num -= 1
return wrapper_repeat
return decorator_repeat