Python 中的变量作用域与 global 声明详解
在 Python 中变量的作用域Scope和命名空间Namespace遵循 LEGB 规则Local → Enclosing → Global → Built-in但一个关键细节常被初学者忽略只要函数内部对某个变量名执行了赋值操作Python 就会将该变量视为局部变量local且在整个函数体中生效——包括该赋值语句之前的读取操作。这就是你遇到 UnboundLocalError: local variable p referenced before assignment 的根本原因。为什么第一段代码报错复制AI写代码1234567p hello# 全局变量def z():ifp hello: # ⚠️ 错误此处尝试读取 p但 Python 已判定 p 是局部变量p 2# 因为下方有赋值所以整个函数中 p 被标记为 localprint(p)z()虽然 p hello 在全局定义但在 z() 内部p 2 这一赋值语句“污染”了整个函数的作用域Python 编译函数时静态分析发现 p 被赋值于是将所有 p 的引用包括 if p hello都绑定到局部命名空间。而此时局部变量 p 尚未被初始化因此读取时报错。为什么后两段代码能正常运行✅ 第二段无条件赋值复制AI写代码12345p hellodef z():p 2# 局部赋值不访问全局 pprint(p) # 输出2完全独立于全局 pz()这里没有读取 p 的动作发生在赋值之前因此无冲突——p 纯粹是局部变量。✅ 第三段读取全局、写入不同变量123456p hellodef z():ifp hello: # ✅ 安全读取的是全局 p无局部赋值干扰x 2# 局部变量 x与 p 无关print(x)z()因为函数内从未对 p 赋值Python 自然沿用 LEGB 规则向上查找到全局 p读取成功。正确修改方式使用 global 声明若你确实需要在函数内修改全局变量 p必须显式声明复制AI写代码12345678910p hellodef z():globalp # ✅ 关键告知 Python “接下来的 p 指向全局变量”ifp hello:p 2print(p)z() # 输出2print(p) # 输出2—— 全局 p 已被修改? 注意global 声明必须出现在函数内所有对该变量的读/写操作之前且仅对当前函数生效。补充nonlocal 的适用场景进阶提示当嵌套函数需修改外层非全局函数的局部变量时应使用 nonlocal而非 global复制AI写代码1234567def outer():x outerdef inner():nonlocal xx inner# 修改 outer 的局部变量 xinner()print(x) # 输出inner总结与最佳实践?判断依据函数内是否对某变量名执行了赋值若有则默认为局部变量。?避免陷阱不要在赋值前读取同名变量除非明确用 global/nonlocal。✅推荐做法优先通过参数传入、返回值传出数据减少全局变量依赖若必须修改全局状态请显式使用 global 并添加注释说明意图利用 IDE 或静态检查工具如 pylint提前捕获此类作用域问题。理解这一机制是写出可维护、无隐式副作用 Python 代码的重要一步。