python函数内出现赋值语句即锁定变量为局部作用域,编译期标记name为局部,后续读取未初始化的局部变量报unboundlocalerror;global声明须在函数首层有效位置,否则无效;可变对象原地修改无需global,重绑定需global;nonlocal仅作用于直接外层函数,与global混用易致绑定混乱。

函数内出现赋值语句,Python编译期就锁定变量为局部作用域
只要函数体中任何位置有 name = ... 或 name += ... 这类赋值操作,Python 在编译函数时(不是运行时)就会把 name 标记为局部变量。后续所有对 name 的读取,哪怕写在赋值语句之前,都按局部变量查找——而此时它还没被初始化,于是报 UnboundLocalError。
这不是“Python 没找到全局变量”,而是它压根不往全局作用域查。例如:
counter = 0
def inc():
print(counter) # ❌ 这里就错了
counter += 1
即使 counter 在模块顶层定义了,counter += 1 这一行已让编译器认定 counter 是局部变量,前面的 print(counter) 就变成读取一个未定义的局部变量。
global 声明必须出现在函数最开头可执行位置
global 不是“运行时开关”,而是编译器识别作用域的关键信号。它必须写在函数体第一层(不能缩进在 if、for 或 try 块内),且所在分支必须实际执行过,否则声明无效。
-
global x写在if False:里 → 编译器忽略,仍当局部变量处理 -
global x写在print(x)后面 → 编译阶段已判定x为局部,声明失效 - 模块顶层没定义
x,只写global x→ 首次赋值成功,但首次print(x)会报NameError(全局名不存在)
可变对象修改不触发 UnboundLocalError,但重绑定会
对 list、dict 等可变对象调用 .append()、.update()、del lst[0],只是改变对象内容,不改变变量绑定关系,所以无需 global。
但一旦出现 =、+=(对不可变对象如 str、int)、-= 等重绑定操作,就必须加 global,否则触发 UnboundLocalError。
常见误判:
-
data.append(1)→ 安全,不需global -
data = [1, 2, 3]→ 危险,重绑定了data,必须global data -
data += [4]→ 对list是就地修改(等价extend),但 Python 仍视作赋值操作,需global
nonlocal 和 global 混用容易导致绑定混乱
nonlocal 只能绑定到**直接外层函数**的作用域,不能跳过一层;global 绑定到模块顶层。如果外层函数本身在模块顶层定义,其局部变量被 nonlocal 引用,又被另一个函数用 global 修改,实际改的是同一内存地址,但语义上极易混淆。
典型陷阱:
- 在顶层函数里用
nonlocal x→ 直接报SyntaxError(无外围非全局作用域) -
nonlocal x写在if False:里 → 编译失败,不等运行就报错 - 外层函数中
x = 1被包在if False:中 → 编译器认为“外层无x定义”,nonlocal x失效
真正难调试的不是语法错误,而是变量看似被改了,却在别的地方读不到——因为 global 和 nonlocal 指向了不同层级的同名绑定,而你没意识到它们根本不是同一个东西。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











