global改不了嵌套函数里的变量,因为它只查找模块级全局变量,跳过外层函数作用域;nonlocal则专用于修改外层函数的局部变量,从直接外层开始向上查找。

global 为什么改不了嵌套函数里的变量
因为 global 只认模块级(顶层)变量,它不会往外层函数作用域里找。你在一个 inner() 函数里写 global x,Python 就直接去模块最外层找 x —— 即使外层 outer() 已经定义了同名的 x,它也视而不见。
常见错误现象:
-
UnboundLocalError: local variable 'x' referenced before assignment(没声明就读,又在同作用域写了赋值) - 函数执行完,外层函数的
x值完全没变 - 误以为
global能“向上穿透多层”,结果改到了一个根本没打算碰的全局变量上
本质是作用域查找规则(LEGB)强制的:global 跳过 E(Enclosing,即嵌套作用域),直奔 G(Global)。
nonlocal 是怎么精准定位到外层局部变量的
nonlocal 的设计目标就是专治“嵌套函数想改上一级局部变量”这个场景。它不看全局,也不看自己,只从当前函数的直接外层作用域开始往上找,找到第一个匹配的变量绑定就停。
实操要点:
-
nonlocal必须用在嵌套函数中,平级函数或模块顶层用会报SyntaxError - 目标变量必须已经在外层函数中被定义过,不能是“先
nonlocal x,再x = 10”——这会触发SyntaxError: no binding for nonlocal 'x' found - 可以一次声明多个:
nonlocal count, state, _buffer - 不可用于类方法内部修改实例或类变量;它只管函数嵌套链上的局部变量
示例对比:
def outer():
x = 10
def inner():
nonlocal x # ✅ 找到 outer() 里的 x
x += 1
inner()
print(x) # 输出 11
什么时候该用 global,什么时候必须用 nonlocal
判断依据只有一个:你想改的那个变量,是在模块顶层定义的,还是在外层函数里定义的?
用 global 的典型场景:
- 维护一个跨多个函数共享的计数器:
config_version、_debug_mode - 单例初始化标志:
_initialized = False,由某个初始化函数设为True - 注意:
global允许首次赋值时自动创建变量,但这是危险习惯,容易拼错名导致静默创建新变量
必须用 nonlocal 的典型场景:
- 闭包工厂函数返回内层函数,且需要保持/更新状态(比如计数器、缓存键)
- 装饰器内部需要修改外层装饰器参数作用域中的变量
- 递归式嵌套回调中维持上下文(如异步状态机)
混淆使用后果严重:用 global 去改嵌套变量 → 改错地方;用 nonlocal 去改全局变量 → 直接语法报错。
可变对象原地修改不用声明,但重绑定仍需 nonlocal
这点特别容易忽略:如果外层变量是列表、字典、自定义对象等可变类型,你在内层函数里调用 .append()、[key] = value、.update() 等原地操作,不需要 nonlocal —— 因为变量本身没变,只是内容变了。
但一旦你做了赋值重绑定,比如 data = [1, 2, 3] 或 cache = new_dict,就必须加 nonlocal data 或 nonlocal cache,否则就新建了一个局部变量。
验证方式很简单:打印 id(data) 前后是否一致。一致说明是原地改;不一致说明发生了重绑定,此时不加 nonlocal 就等于放弃对外层变量的控制权。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











