作用域
约 1148 字大约 4 分钟
2026-08-13
作用域(Scope)决定了程序中变量和名字的可见范围。理解作用域能帮助你预测代码的执行结果,避免变量名冲突。
LEGB 规则
Python 查找变量时遵循 LEGB 规则,按以下优先级顺序搜索:
| 优先级 | 层级 | 说明 |
|---|---|---|
| 1 | Local | 函数内部(局部作用域) |
| 2 | Enclosing | 嵌套函数的外层函数(闭包) |
| 3 | Global | 模块级别(全局作用域) |
| 4 | Built-in | Python 内置(如 len、print) |
x = "global" # G:全局作用域
def outer():
x = "enclosing" # E:外层函数作用域
def inner():
x = "local" # L:局部作用域
print(x) # 按 L → E → G → B 查找
inner()
outer() # local局部作用域(Local)
函数内部定义的变量,只在函数内部可见:
def demo():
local_var = 100 # 局部变量
print(local_var)
demo() # 100
# print(local_var) # NameError!函数外部访问不到函数参数也是局部变量:
def greet(name): # name 是局部变量
message = f"Hello, {name}" # message 也是局部变量
print(message)
greet("Alice")
# print(name) # NameError!全局作用域(Global)
模块级别(文件最外层)定义的变量:
count = 0 # 全局变量
def increment():
print(count) # 读取全局变量,OK
increment() # 0在函数内修改全局变量
直接赋值会创建局部变量,而非修改全局变量:
count = 0
def wrong_increment():
count += 1 # UnboundLocalError!
# wrong_increment()使用 global 关键字声明:
count = 0
def increment():
global count # 声明使用全局变量
count += 1
print(count)
increment() # 1
increment() # 2
print(count) # 2闭包作用域(Enclosing)
嵌套函数中,内层函数可以访问外层函数的变量:
def outer():
x = "outer" # 外层函数的局部变量
def inner():
print(x) # 访问外层变量
inner()
outer() # outer修改外层变量
内层函数不能直接修改外层变量:
def counter():
count = 0
def increment():
count += 1 # UnboundLocalError!
increment()
# counter()使用 nonlocal 关键字:
def make_counter():
count = 0
def increment():
nonlocal count # 声明使用外层变量
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3nonlocal vs global:
| 关键字 | 作用 |
|---|---|
global | 声明变量来自全局作用域 |
nonlocal | 声明变量来自外层函数作用域 |
常见错误
错误 1:在函数内同时读写全局变量
x = 10
def demo():
print(x) # 先读
x = 20 # 再写 → 编译期就判定 x 是局部变量!
# demo() # UnboundLocalError原因: Python 在编译函数时就确定了变量作用域,一旦函数内有赋值语句,该变量就被视为局部变量。
修正:
x = 10
def demo():
global x
print(x)
x = 20
demo() # 10
print(x) # 20错误 2:默认参数的陷阱
def add_item(item, items=[]):
items.append(item)
return items
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] —— 意外!列表被共享了默认参数在函数定义时求值,只创建一次。
修正:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items作用域速查
# 1. 简单函数
name = "global"
def func():
name = "local" # 局部变量,不影响全局
print(name) # local
func()
print(name) # global
# 2. 嵌套函数
def outer():
name = "outer"
def inner():
name = "inner" # 自己的局部变量
print(name) # inner
inner()
print(name) # outer
outer()
# 3. 使用 nonlocal
def outer():
name = "outer"
def inner():
nonlocal name
name = "modified" # 修改外层变量
inner()
print(name) # modified
outer()作业
作业一:作用域判断
阅读以下代码,预测每行 print 的输出结果,并在注释中写出你的答案。
x = 1
def func_a():
x = 2
def func_b():
print(x) # ?
func_b()
print(x) # ?
func_a()
print(x) # ?作业二:global 与 nonlocal
阅读以下代码,预测输出结果:
count = 0
def outer():
count = 10
def inner():
global count
count += 1
print(count) # ?
inner()
print(count) # ?
outer()
print(count) # ?作业三:修复代码
以下代码用于统计函数调用次数,先读取全局计数器打印日志,再递增计数。但实际运行会报错,请修改使其正确运行:
call_count = 0
def process_data(data):
result = sum(data)
# 处理完成后递增计数器
call_count += 1
return result
print(process_data([1, 2, 3]))
print(process_data([4, 5, 6]))
print(f"总共调用了 {call_count} 次")作业四:闭包计数器
实现一个函数 make_multiplier(n),返回一个函数。返回的函数接收一个参数 x,返回 n * x。
要求使用闭包实现,不要使用 global。
triple = make_multiplier(3)
print(triple(5)) # 15
print(triple(10)) # 30
double = make_multiplier(2)
print(double(7)) # 14作业五:综合练习
实现一个函数 create_account(initial_balance),返回两个字典:
deposit(amount): 存款,返回新余额withdraw(amount): 取款,余额不足返回"余额不足",否则返回新余额
要求使用闭包保存余额状态,不要暴露余额变量。
deposit, withdraw = create_account(100)
print(deposit(50)) # 150
print(withdraw(30)) # 120
print(withdraw(200)) # 余额不足