Python 3:变量在范围内重新定义时变得无法解析

Python 3: Variable becomes unresolved when redefined in scope

我正在编写一个装饰器,如果我尝试在任何地方重新定义它们中的任何一个,内部函数会出现一些具有可变范围的奇怪行为。

def decorate_me(a_variable: bool):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):

            print(a_variable)
            new_variable = not a_variable
            new_variable = not new_variable
            print(new_variable)

            return func(*args, **kwargs)

        return wrapper
    return decorator

按预期工作,没有问题。但是,如果在最后重新定义 a_variable:

def decorate_me(self, a_variable: bool):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):

            print(a_variable)
            new_variable = not a_variable
            new_variable = not new_variable
            print(new_variable)
            
            # --- --- --- --- --- ---
            # THIS LINE RIGHT HERE
            # --- --- --- --- --- ---
            a_variable = not a_variable

            return func(*args, **kwargs)

        return wrapper
    return decorator

这引发了一个错误:

File "...", line 41, in wrapper
    print(a_variable)
UnboundLocalError: local variable 'a_variable' referenced before assignment

重新定义变量如何导致它在重新定义之上几行的语句上解除绑定?这里的规则是什么?如何避免?

这在 Python FAQ, and explained here by Eli Bendersky 中得到了回答。这是当你 google 'Python UnboundLocalError'.

时出现的第一件事

来自 Python 的常见问题解答:

This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new value to x, the compiler recognizes it as a local variable. Consequently when the earlier print(x) attempts to print the uninitialized local variable and an error results.

简单地说,重新定义变量就是重新定义它的作用域,从而从外部作用域中移除变量。

解决这个问题的方法是使用 globalnonlocal 关键字。在所讨论的示例中,global 将不起作用(因为 a_variable)不是全局的,但 nonlocal 将起作用。明确地,它告诉内部函数使用外部作用域中的变量。

Eli Bendersky 的解释更深入地解释了为什么会发生这种情况,值得一读。