【问题标题】:Decorator working with for loop but not with while loop装饰器使用 for 循环但不使用 while 循环
【发布时间】:2020-07-08 13:33:34
【问题描述】:

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

    不同之处在于带有while 的版本分配了num_times 变量。这使得它在默认情况下对wrapper_repeat() 函数是本地的,因此它与来自repeat()num_times 变量不同。您需要将其声明为非本地:

    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
    

    【讨论】:

      猜你喜欢
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      • 2011-07-10
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多