python 3 中的嵌套函数内部变量如何工作?

how local variables work inside nest function in python 3?

我有代码:

def main(m):
    res = m
    def help(a, b):
        print(res)
        #res = min(res, a*b)
    help(3,2)
    return res
main(3)

代码有效。不过

def main(m):
    res = m
    def help(a, b):
        print(res)
        res = min(res, a*b)
    help(3,2)
    return res
main(3)

提高UnboundLocalError: local variable 'res' referenced before assignment

def main(m):
    global res
    res = m
    def help(a, b):
        print(res)
        res = min(res, a*b)
    help(3,2)
    return res
main(3)

好像我加了global res也没变。这里发生了什么?如何在函数 help?

中更新 res

问题是您在 help() 函数中引入了一个新的、未初始化的局部变量,然后试图将其传递给 min(res, a*b) 函数。

您可以 return min(res, a*b) 并将其分配给 help() 函数之外的 res,而不是尝试处理范围问题:

def main(m):
    res = m
    def help(a, b):
        # print(res)
        return min(res, a*b)
    res = help(3,2)
    return res

你需要告诉内部函数 res 变量是非本地的,像这样:

def main(m):
    res = m
    def help(a, b):
        nonlocal res
        print(res)
        res = min(res, a*b)
    help(3,2)
    return res
main(3)

您可以在函数中读取非局部作用域变量而不会出现问题,但如果您尝试写入变量,则 python 假定您要创建一个新的局部作用域变量。该局部变量隐藏并阻止访问可能存在于更高范围的命名空间中的任何类似命名的变量,例如外部函数或全局变量。要通知它您不想创建局部变量并想访问外部范围变量,您需要使用 nonlocal 关键字,如上例所示。

使用 global res 无法修复它,因为全局变量位于命名空间层次结构的顶层,而您尝试访问的 res 变量不是。您要访问的 res 位于全局范围和本地范围之间。这就是为什么您需要使用 nonlocal 而不是 global。如果 res 处于 top/external 级别,那么 global 就是解决方案。

这里的相关代码是

res = m
def help(a, b):
    print(res)
    res = min(res, a*b)  # may or may not be commented out

这不是你想的那样。

让我们逐行分析一下:

  1. res = m:这定义了变量 res,值为 m,它存在于 main 函数
  2. def help(a, b):开始一个函数定义。在 help 函数中,您可以定义与 main
  3. 中的变量隔离的全新变量
  4. print(res):打印变量 res 的值。要查找 res 的值,Python 将首先在 help 函数中查找名为 res 的变量。如果有 none,它将在 main 函数(即父作用域)中搜索名为 res 的变量。 (如果有none 那里,它会继续搜索越来越高的范围。)事实证明,在你的例子中,是否有一个变量在help函数中命名为res取决于第4行是否被注释掉!
  5. res = min(res, a*b):这与您认为的不同。你想要它做的是改变main函数中res变量的变量值。但是,Python 将在 help 函数中创建一个 new 变量 res 并将其值设置为 min(res, a*b).

这就是您获得 UnboundLocalError 的原因。因为当第 4 行取消注释时,print(res) 指的是 help 函数中名为 res 的变量,而不是 main 函数。但是当第4行被注释掉时,help函数中没有res变量,所以print(res)改用main函数中的变量

那么,如何解决呢?其实很简单,把代码改成:

def help(a, b):
    nonlocal res
    print(res)
    res = min(res, a*b)

nonlocal 语句告诉 Python,“嘿,res 变量来自外部作用域”。