You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python nonlocal关键字:为何有时需要声明有时无需声明

关于Python中nonlocal关键字的作用域困惑解析

这个问题其实戳中了Python作用域规则里一个很容易踩坑的点,我来给你拆解清楚:

核心原因:Python对「变量赋值」和「变量读取」的作用域处理逻辑不一样

Python的作用域查找遵循LEGB规则(局部Local → 嵌套外层Enclosing → 全局Global → 内置Built-in),但这里的关键差异在于:

  • 当你在函数内读取一个变量时,Python会按LEGB顺序逐层查找,找不到才会报错;
  • 但当你在函数内赋值一个变量时,Python默认会把这个变量标记为当前函数的局部变量,它不会再去外层作用域查找——除非你用nonlocal或global明确声明变量的来源。

对应到你的代码场景

假设你的代码结构大概是这样(简化版):

def outer_function():
    records = []  # 外层函数的变量
    
    def inner_function():
        # 第276行:如果不写 nonlocal records
        # 第277行:records = some_value (赋值操作)
        records = process_data()  # 这里会报错:未定义records
        
        # 第289行:比如 for item in records (读取操作)
        for item in records:
            print(item)
    
    inner_function()
  1. 第277行赋值报错的原因:
    当你直接写records = ...时,Python会认为这是在inner_function内部定义一个新的局部变量records。但在赋值语句之前,这个局部变量还没被创建,所以会抛出"未定义"的错误——它完全不会去外层找那个已经存在的records。

  2. 第289行读取正常的原因:
    如果你只做读取操作(比如遍历records),Python会先在inner_function的局部作用域找,找不到就自动跳到外层的outer_function作用域,刚好那里有定义好的records,所以能正常读取,不会报错。

  3. 加了nonlocal就正常的原因:
    nonlocal records这句话明确告诉Python:"这个records不是当前函数的局部变量,它来自外层嵌套函数的作用域"。这样Python就会在外层找到records,赋值操作也会直接修改外层的这个变量,不会再当作局部变量处理。

再举个极简的验证例子

你可以运行这段代码感受一下差异:

def outer():
    x = 10
    def inner():
        print(x)  # 读取操作:正常输出10,因为Python会找外层的x
        x = 20    # 赋值操作:如果没有nonlocal,这里会报错
    inner()

outer()

运行它会直接报错,但如果在inner函数开头加nonlocal x,就能正常修改外层的x,输出10后,外层的x会变成20。

内容的提问来源于stack exchange,提问作者uoay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 09:57:36