Python变量查找严格遵循LEGB规则:Local→Enclosing→Global→Built-in;函数内赋值即标记为local,读取前赋值会报UnboundLocalError;global仅作用于模块级,nonlocal限于直接外层函数。

Python 中变量查找的 LEGB 规则是什么
Python 查找变量时严格遵循 LEGB 顺序:Local → Enclosing → Global → Built-in。这不是可配置的行为,而是解释器硬编码的解析逻辑。只要没被 global 或 nonlocal 显式声明,名字绑定就按这个顺序向上查找。
- Local:当前函数内部定义的变量(包括参数)
- Enclosing:外层嵌套函数的作用域(仅对闭包有效)
- Global:模块顶层定义的变量(即“全局变量”,实际是模块级)
- Built-in:Python 内置命名空间,如
len、print、Exception
注意:import 语句导入的模块名也进入 global 命名空间,但模块内部的变量不会自动“泄露”进来。
为什么在函数里修改全局变量会报 UnboundLocalError
这是最容易踩的坑:只要函数内对某个变量名做了赋值(哪怕只在某条分支中),Python 就会将该名字标记为 local 变量,整个函数体都按 local 查找——此时若在赋值前读取它,就会触发 UnboundLocalError。
x = 10
def f():
print(x) # ← 这里报错:UnboundLocalError: local variable 'x' referenced before assignment
if False:
x = 20
原因不是“条件没走”,而是编译阶段已确定 x 是 local(因为函数体内存在 x = ...)。解决方法只有两个:
立即学习“Python免费学习笔记(深入)”;
- 真想读全局
x,就在函数开头加global x - 真想读又写,且不希望影响全局,就显式读取
globals()['x'](不推荐,破坏可读性)
global 和 nonlocal 的作用边界在哪
global 只能指向模块级变量,不能跨模块;nonlocal 只能指向直接外层函数的局部变量,不能跳层或指向 global。
-
global x:把当前作用域中的x绑定到模块顶层的x,读写都操作它 -
nonlocal x:把当前作用域中的x绑定到最近一层 enclosing 函数中定义的x
x = "module"
def outer():
x = "outer"
def inner():
nonlocal x
print(x) # → "outer"
x = "inner"
inner()
print(x) # → "inner"
如果把 nonlocal x 换成 global x,inner() 中的 print(x) 输出的就是 "module",且 outer 内的 x 不受影响。
模块级变量真的是“全局”的吗
不是。Python 没有进程级全局变量,只有模块级。每个模块都有独立的 global 命名空间。不同文件里的同名变量互不影响,除非显式导入或通过 sys.modules 访问。
-
from mod import x:导入的是x的值(对象引用),不是引用本身 -
import mod:导入模块对象,mod.x才是动态访问
常见误解:在一个模块里改了 config.DEBUG = True,以为所有地方都能立刻看到。其实其他模块如果已执行 from config import DEBUG,拿到的是旧引用,不会自动更新。
真正共享状态,得用可变对象(如字典、类实例)或单例模式,而不是依赖变量名重绑定。









