Decorator使用for循环,但不使用while循环

问题描述 投票:2回答:1

我正在尝试学习如何在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

对我来说,这些功能应该完全相同,但事实并非如此。您可以帮助我了解我的代码有什么问题吗?

谢谢!

python python-3.x loops python-decorators
1个回答
2
投票

区别在于,带有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
© www.soinside.com 2019 - 2024. All rights reserved.