
Python 的作用域遵循 LEGB 规则 ,即:L → E → G → B(由内向外查找)。
一、四种作用域
| 作用域 | 英文 | 说明 | 示例 |
|---|---|---|---|
| Local | 局部作用域 | 函数内部定义的变量 | def func(): x = 1 |
| Enclosing | 闭包/嵌套作用域 | 外层嵌套函数的变量 | 嵌套函数中访问外层函数的变量 |
| Global | 全局作用域 | 模块顶层定义的变量 | 脚本中 x = 1 |
| Built-in | 内置作用域 | Python 内置的名称 | print()、len()、range() |
二、详细说明
1. Local(局部作用域)
函数内部定义的变量,只能在函数内部访问。
def my_func():
x = 10 # 局部变量
print(x) # 可以访问
my_func()
# print(x) # NameError: name 'x' is not defined
特点:
-
函数调用时创建,函数返回时销毁
-
不同函数的局部变量互不干扰
def func_a():
x = 10
return xdef func_b():
x = 20 # 与 func_a 的 x 不同,互不影响
return xprint(func_a()) # 10
print(func_b()) # 20
2. Enclosing(闭包/嵌套作用域)
在嵌套函数中,内层函数可以访问外层函数的变量。
def outer():
x = 10 # enclosing 变量
def inner():
print(x) # 可以访问外层变量
inner()
outer() # 10
修改 enclosing 变量
def outer():
x = 10
def inner():
nonlocal x # 声明要修改外层变量
x = 20
inner()
print(x) # 20
outer()
3. Global(全局作用域)
在模块顶层定义的变量,可以在整个模块中访问。
x = 10 # 全局变量
def my_func():
print(x) # 可以访问全局变量
my_func() # 10
修改全局变量
x = 10
def my_func():
global x # 声明要修改全局变量
x = 20
my_func()
print(x) # 20
模块级别的全局变量
# file: config.py
MAX_SIZE = 100
DATABASE_URL = "sqlite:///db.sqlite"
# file: main.py
import config
print(config.MAX_SIZE) # 100
4. Built-in(内置作用域)
Python 预定义的名称,在任何地方都可以直接使用。
# 内置函数
print("Hello")
len([1, 2, 3])
range(5)
# 内置异常
ValueError
TypeError
# 内置常量
True
False
None
查看所有内置名称
print(dir(__builtins__))
# ['ArithmeticError', 'AssertionError', 'BaseException', ...]
三、作用域规则
1. 变量查找顺序(LEGB)
x = "global" # Global
def outer():
x = "enclosing" # Enclosing
def inner():
x = "local" # Local
print(x) # 输出: local(先找到 Local)
inner()
outer() # local
2. 逐级查找过程
x = "global"
def outer():
x = "enclosing"
def inner():
# 1. 先查 Local → 没有 x
# 2. 再查 Enclosing → 有 x = "enclosing"
# 3. 不会继续往上查
print(x) # 输出: enclosing
inner()
outer()
3. 不同作用域同名变量的遮蔽
x = "global" # Global
def outer():
x = "enclosing" # Enclosing(遮蔽 Global)
def inner():
x = "local" # Local(遮蔽 Enclosing)
print(x)
inner()
print(x) # enclosing
outer()
print(x) # global
四、作用域相关关键字
1. global 关键字
用于在函数内部修改全局变量。
count = 0
def increment():
global count # 声明 count 是全局变量
count += 1
increment()
print(count) # 1
2. nonlocal 关键字
用于在嵌套函数中修改外层函数的变量。
def outer():
x = 10
def inner():
nonlocal x # 声明 x 是外层变量
x = 20
inner()
print(x) # 20
outer()
3. 常见错误:忘记声明
x = 10
def func():
# 错误!这会在局部作用域创建新变量,不会修改全局变量
x = 20 # 这是局部变量,不是修改全局
func()
print(x) # 10(全局变量未被修改)
x = 10
def func():
global x # 正确
x = 20
func()
print(x) # 20
五、作用域与数据类型
1. 可变对象的修改不需要 global
my_list = [1, 2, 3]
def append_item():
# 修改列表内容,不需要 global
my_list.append(4)
append_item()
print(my_list) # [1, 2, 3, 4]
# 但如果要重新赋值,就需要 global
def reassign():
global my_list
my_list = [5, 6, 7] # 重新赋值
2. 不可变对象必须用 global
count = 0
def increment():
global count
count += 1 # 整数是不可变对象,需要重新赋值
六、注意事项
1. 条件语句不创建作用域
if True:
x = 10 # 即使缩进,x 还是在全局作用域
print(x) # 10(不是错误!)
for i in range(5):
pass
print(i) # 4(循环变量会泄露到外层)
七、对比表
| 作用域 | 位置 | 访问方式 | 修改关键字 |
|---|---|---|---|
| Local | 函数内部 | 直接访问 | - |
| Enclosing | 外层嵌套函数 | 直接访问(读) | nonlocal(写) |
| Global | 模块顶层 | 直接访问(读) | global(写) |
| Built-in | Python 内置 | 直接访问 | 不能修改 |
查找顺序:
LEGB:Local → Enclosing → Global → Built-in
修改规则:
读变量,按 LEGB 找;写变量,默认只在 Local 改。
想改外层用 nonlocal,想改全局用 global。
核心点:
-
Python 使用 静态作用域(词法作用域)
-
变量赋值默认在当前作用域创建/修改
-
访问变量按 LEGB 顺序查找
-
global和nonlocal用于修改外层变量 -
循环、条件语句不创建新作用域