四种作用域:LEGB
Python 查找变量按这个顺序:
L Local 当前函数内部
E Enclosing 外层函数(嵌套时)
G Global 模块顶层(文件全局)
B Built-in 内置(print / len / range 等)
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
print(x) # enclosing
outer()
print(x) # global
函数里能"看见"全局,但默认不能"改"
count = 0
def add():
print(count) # OK,能读
count += 1 # UnboundLocalError!
为什么?只要函数体里有 count = ... 赋值,Python 就把 count 当成局部变量——但读那行时局部变量还没值。
global:声明"我要改全局变量"
count = 0
def add():
global count
count += 1
add()
add()
print(count) # 2
⚠️ 慎用 global——容易让代码难以追踪。优先:返回值 + 重新赋值。
nonlocal:改外层函数的变量
def make_counter():
count = 0
def increment():
nonlocal count # 不是 global!是上一层函数的
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
闭包
内层函数"记住"了外层的变量——这就是闭包:
def multiplier(n):
def mul(x):
return x * n # 记住了外层的 n
return mul
double = multiplier(2)
triple = multiplier(3)
double(5) # 10
triple(5) # 15
闭包是装饰器、回调函数的基础。
实战:避免命名冲突
# 不好:函数内变量名和参数撞车
def f(list): # 覆盖了内置 list!
list.append(1)
# 好:换个名字
def f(items):
items.append(1)
下一篇讲文件读写——把数据存到磁盘。