Python函数内同名变量报UnboundLocalError,因编译期将赋值变量标记为局部,读取在赋值前则出错;global用于模块级变量,nonlocal用于最近外层函数变量,二者不可混用且需提前声明。

为什么在函数里修改同名变量会报 UnboundLocalError
Python 在编译函数时,只要看到某个变量在函数体内有赋值操作(哪怕只在 if 分支里),就会把它标记为局部变量。之后如果在赋值前就尝试读取它,就会触发 UnboundLocalError: local variable 'x' referenced before assignment。
这不是运行时才判断的作用域问题,而是编译期就确定的——所以即使 if False: 里写了 x = 1,整个函数里的 x 也会被当成局部变量,导致前面的 print(x) 报错。
- 常见错误现象:
UnboundLocalError出现在读取变量位置,但根源在后面某处的赋值语句 - 不是“没定义”,而是“被识别为局部变量但还没赋值”
-
global和nonlocal不是补救措施,而是提前声明意图的必要手段
什么时候用 global,什么时候必须用 nonlocal
global 声明变量属于模块作用域(即顶层作用域),nonlocal 声明变量属于**最近一层外层函数**的作用域。二者不能混用,且 nonlocal 不能指向全局变量。
- 外层是模块级变量 → 用
global x - 外层是嵌套函数里的变量(非全局)→ 必须用
nonlocal x,用global会创建/修改全局变量,不是你想要的 -
nonlocal查找从当前函数的直接外层开始,逐层向外,不跳过中间层;找不到对应变量名会报SyntaxError - 不能对未声明的变量先读再写:即使加了
nonlocal,也得确保外层确实定义了该变量
示例:
def outer():
x = 10
def inner():
nonlocal x # ✅ 正确:x 在 outer 中定义
print(x) # 输出 10
x += 1 # 修改 outer 的 x
inner()
print(x) # 输出 11
global/nonlocal 的典型误用和坑
这两个关键字本身不难,但实际用错的地方很隐蔽,尤其在条件分支、循环或异常处理中。
- 在 if/else 中只有一边用了赋值 → 整个函数仍把变量判为局部,另一边读取就报错(
global/nonlocal声明必须出现在函数顶部,不能放在分支里) - 写了
global x,但模块顶层根本没定义x→ 第一次赋值没问题,但首次读取会报NameError(因为全局变量不存在) - 多层嵌套时误以为
nonlocal可以跨两层 → 实际只能绑定到直接外层;想改更外层要用多个nonlocal链式声明 - 类方法里对实例属性误用
nonlocal→ 实例属性走的是self.x,和闭包变量无关,这里用nonlocal会直接报错
比 global/nonlocal 更安全的替代方案
过度依赖 global 或 nonlocal 往往说明设计可以优化。真要共享状态,优先考虑这些方式:
- 把变量封装进类:用实例属性替代闭包变量,逻辑更清晰,也避免作用域混淆
- 用可变容器传参:比如传入一个
dict或list,在函数内修改其内容,不涉及变量重新绑定 - 返回新值而非原地修改:函数专注计算,由调用方决定是否更新外层变量
- 用
functools.partial或闭包工厂函数预绑定参数,减少运行时变量捕获复杂度
真正需要 nonlocal 的场景其实不多,多数是计数器、状态标志这类简单闭包;一旦逻辑变复杂,就该考虑重构了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











