【问题标题】:how local variables work inside nest function in python 3?局部变量如何在 python 3 的嵌套函数中工作?
【发布时间】:2026-02-18 06:10:01
【问题描述】:

我有代码:

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

【问题讨论】:

  • 问题在于,添加行 res = min(res, a*b) 实际上在 help 函数中引入了一个新变量 res,它与 @ 中的变量 res 不同 987654333@。我会在几秒钟内写一个完整的答案。
  • 这能回答你的问题吗? Short description of the scoping rules?

标签: python-3.x local-variables nested-function


【解决方案1】:

你需要告诉内部函数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 位于顶层/外部级别,那么global 将是解决方案。

【讨论】:

  • 酷,知道为什么我添加 global res 不起作用吗?
  • @jason 因为全局变量位于命名空间层次结构的顶层,而您尝试访问的 res 不是。您正在访问的 res 位于全局范围和本地范围之间。这就是为什么您需要使用非本地而不是全局的原因。我已经编辑了我的答案,以包括我一开始遗漏的解释。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    这里的相关代码是

    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. print(res):这将打印变量 res 的值。为了找到res 的值,Python 将首先在help 函数中查找名为res 的变量。如果没有,它将在main 函数(即父作用域)中搜索名为res 的变量。 (如果没有那里,它将继续搜索越来越高的范围。)事实证明,在您的示例中,@ 中是否存在名为 res 的变量987654337@函数取决于第4行是否被注释掉!
    4. 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 变量来自外部作用域”。

    【讨论】:

    • 优秀的解释。我可以在help() 函数之前添加global res 以将res 变成一个全局变量吗?
    • 是的,可以。但是,从您的代码的外观来看,在任何地方都没有global 语句和help 函数中的单个nonlocal res 语句会更合适。 (既然你return res 来自main,那么res 真的应该是一个全局变量吗?)
    • 我尝试在help()之外添加global res,它仍然会引发错误。
    • 我看错了你的问题。添加global res outside help 将不起作用,因为那时您指的是main 函数中的res。我在回答中提供了一个解决方案,你试过了吗?