Python装饰器中变量的作用域 - 改变参数

5

我有以下带参数的装饰器:

from functools import wraps
def pdecor(p):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            p -= 1
            return fn(*args, **wargs)
        return wrapper
    return decorator

尝试使用装饰器会导致以下问题:
>>> @pdecor(1)
... def run(): pass
...
>>> run()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in wrapper
UnboundLocalError: local variable 'p' referenced before assignment
>>>

为什么我不能改变 p

可能是Python变量作用域问题的重复。 - user395760
请查看以下链接:https://dev59.com/F2oy5IYBdhLWcg3wl_Ix - Danica
1个回答

10
因为你在wrapper函数内部分配了p的值,所以Python将wrapper内部的p视为局部变量。 在Python 3中,您可以使用nonlocal pp标记为从外部作用域引用。 在Python 2中,无法对中间的p进行赋值,尽管可以通过将其作为关键字参数传递给嵌套函数来获取对相同值的引用(例如,def decorator(fn,p = p))。
然而,你想表达什么并不清楚。 p已经只是pdecor内部的局部变量,因此没有任何代码可以访问p,因此将其递减不会影响其他任何地方的代码。 因此,无论您是否可以递减p,它都不会实现任何目标。

最初我想编写一个“重试”装饰器,它会尝试运行给定次数的函数。所以我会尝试运行 fn 并在 fn 引发异常时将 p 减少,直到我用完 p 次重试或 fn 成功为止。然而现在我很高兴 Python 没有让我这样做,否则所有装饰函数的执行都会共享相同的重试计数器,对吧? - Zaar Hai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接