Python3 命名空间与作用域
名字(变量名)与对象的对应关系存放在"命名空间"里:函数内、模块内、内置各有各的 空间。Python 按 LEGB 规则逐层查找名字,理解它才能读懂变量遮蔽与 global/nonlocal。
什么是命名空间
命名空间是"名字 → 对象"的映射表,主要分三类:
- 局部命名空间:函数/类内部定义的名字。
- 全局命名空间:模块顶层定义的名字。
- 内置命名空间:print、len 等内置函数所在的空间。
LEGB 查找顺序
引用名字时按 局部(Local) → 外层(Enclosing) → 全局(Global) → 内置(Built-in) 顺序查找:
x = 10 # 全局命名空间
def show():
x = 99 # 局部命名空间
print(x) # 输出:99(局部优先)
show()
print(x) # 输出:10(全局未被修改)
局部变量遮蔽全局
函数内赋值只会创建新的局部变量,不会改动同名全局变量:
count = 0
def add_one():
count = 1 # 新的局部变量,遮蔽全局
return count
print(add_one()) # 输出:1
print(count) # 输出:0(全局没变)
global:修改全局变量
想在函数内修改全局变量,必须先声明 global:
count = 0
def add_one():
global count # 声明操作的是全局 count
count += 1
add_one()
add_one()
print(count) # 输出:2
nonlocal:修改外层函数变量
内层函数要修改外层函数的局部变量,用 nonlocal:
def outer():
num = 0
def inner():
nonlocal num # 指向 outer 里的 num
num += 1
return num
return inner # 返回内层函数(闭包)
f = outer()
print(f()) # 输出:1
print(f()) # 输出:2
各作用域综合示例
x = "global" # 全局
def outer():
x = "enclosing" # 外层(Enclosing)
def inner():
x = "local" # 局部(Local)
print(x) # 输出:local
inner()
print(x) # 输出:enclosing
outer()
print(x) # 输出:global
小结:名字查找遵循 LEGB(局部→外层→全局→内置);只读外层名字不必声明,要修改 全局变量用 global,修改嵌套外层变量用 nonlocal。