问题: 描述一下 global 和 nonlocal

👇 点击展开/折叠 面试背诵模板(建议先背这个) global 用于在函数内部声明一个变量来自全局作用域,允许修改全局变量;nonlocal 用于在嵌套函数中声明一个变量来自最近的外层函数(非全局),允许修改外层函数的局部变量。两者均需在首次使用前声明,且 nonlocal 不能用于全局作用域,global 不能用于已存在的局部变量。nonlocal 仅适用于嵌套函数场景,且不能绑定全局变量或模块级变量。
---

global 使用场景与代码示例

1
2
3
4
5
6
7
8
x = 10          # 全局变量

def outer():
global x # 声明 x 是全局变量
x = 20 # 修改全局 x

outer()
print(x) # 20(全局变量被修改)

nonlocal 使用场景与代码示例

1
2
3
4
5
6
7
8
9
def outer():
y = 10 # 外层函数的局部变量

def inner():
nonlocal y # 声明 y 来自外层函数
y = 20 # 修改外层函数的局部变量

inner()
print(y) # 20(外层变量被修改)

global 与 nonlocal 的核心对比

维度 global nonlocal
作用域 全局作用域(模块级) 最近的外层函数(非全局)
适用场景 函数内修改模块级变量 闭包或嵌套函数中修改外层变量
能否用于嵌套函数 ✅ 可以,但指向全局 ✅ 可以,指向最近的外层函数
能否在模块级使用 ❌ 不允许(模块级无意义) ❌ 不允许(无外层函数)
声明位置 函数内部,在访问前声明 嵌套函数内部,在访问前声明

常见错误与陷阱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ❌ 错误1:nonlocal 用于全局变量
x = 10
def func():
nonlocal x # SyntaxError: no binding for nonlocal 'x' found

# ❌ 错误2:global 用于已存在的局部变量
x = 10
def func():
x = 20 # 局部变量,遮蔽全局
global x # SyntaxError: name 'x' is assigned to before global declaration

# ✅ 正确:global 声明必须在赋值之前
def func():
global x # 先声明
x = 20 # 再修改

# ❌ 错误3:nonlocal 指向不存在的变量
def outer():
def inner():
nonlocal z # NameError: no binding for nonlocal 'z' found

使用场景速览

场景 推荐方案 替代方案
修改模块级配置变量 global 将变量封装为类属性或模块属性
闭包中维护计数器 nonlocal 使用列表 [0] 或可变对象(hack)
装饰器中保存状态 nonlocal 使用 functools.wraps 配合属性
全局单例初始化 global 改用模块级全局变量或类静态方法

与 globals() 和 locals() 的关系

  • globals() 返回全局命名空间字典,通过 globals()['x'] = 20 等效于 global x; x = 20,但不够优雅。
  • locals() 返回当前局部命名空间字典,但修改它通常不会影响实际变量(Python 优化),不推荐使用。
  • global 和 nonlocal 是编译期指令,影响变量的作用域解析规则,而 globals()/locals() 是运行时函数,用于动态访问命名空间。