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

Python中为什么变量需要nonlocal关键字而列表不需要?

核心原因:Python作用域判断逻辑只看「变量本身是否被赋值」,和你是否修改它指向的对象内容无关

Python在编译函数代码的时候,会扫描整个函数内的所有变量:

  • 只要你在函数内任意位置对某个变量做了直接赋值(比如a = xxx、a += xxx这种会改变变量本身指向的操作),又没有提前用global/nonlocal声明,Python就会默认把这个变量判定为当前函数的局部变量。
  • 如果你只是读取变量的值,或者读取后修改它指向的可变对象的内部属性/元素,没有对变量本身做赋值,Python就不会把它标记为局部变量,会自动去外层作用域查找这个变量。

两种场景的差异解析

1. 为什么a += 1会报错

a += 1本质是对变量a本身的直接赋值,会改变a的指向。所以编译bar函数的时候,Python就把a标记成了bar的局部变量。运行时执行到这一行,需要先读取右边a的值做加法,但是此时局部变量a还没有被初始化赋值,自然就抛出UnboundLocalError。

2. 为什么l[0][0] -= 1不会报错

l[0][0] -= 1全程没有对变量l本身做任何赋值操作:

  • 第一步是读取变量l的值,拿到它指向的外层嵌套列表对象
  • 第二步是修改这个列表对象内部的元素值
    整个过程你没有给l赋新值,也没有改变l本身的指向,所以Python不会把l标记为chicken的局部变量,读取l的时候会正常去外层egg函数的作用域查找,当然不会报错。

拓展验证

如果你真的在chicken里对l本身做赋值,一样会触发错误,比如下面的代码就会抛UnboundLocalError:

def egg():
    l = [[1 for _ in range(3)] for _ in range(3)]
    def chicken():
        l = [] # 对l本身赋值,触发局部变量判定
        l[0][0] -= 1
        print(l)
    chicken()

egg()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 06:51:04