1. 引言
在 Python 中,变量并不直接"存储数据",而是作为名称(name)绑定到对象(object)。
因此,程序执行的本质是不断建立、查找与修改这种"名称 → 对象"的绑定关系。
在函数内部进行变量赋值时,Python 默认将该变量视为局部变量 。
这会导致一个常见问题:如何在函数内部修改外部作用域中的变量?
为解决这一问题,Python 提供了两个关键字:
global------ 用于声明全局变量nonlocal------ 用于声明外层函数变量
本文将从语义、机制与实践角度,对二者进行系统分析。
2. 作用域与变量绑定基础
-
作用域(Scope)
作用域是指程序中变量名称可被访问的区域。Python 采用词法作用域(lexical scope),变量查找遵循 LEGB 规则。
-
LEGB 查找规则
当访问一个变量时,Python 按以下顺序查找:
pythonL → Local(当前函数作用域) E → Enclosing(外层函数作用域) G → Global(模块全局作用域) B → Builtins(内置作用域) -
赋值行为的重要特性
需要特别强调:
变量赋值不会沿 LEGB 向外查找,而是默认在当前局部作用域创建新绑定。
例如:
pythonx = 10 def func(): x = 20此时:
func内部的x是局部变量- 外部的
x不会被修改
3. global 关键字
-
定义
global用于在函数内部声明某个变量属于全局作用域,从而允许对其进行修改或重新绑定。 -
基本示例
pythonx = 10 def func(): global x x = 20 func() print(x)输出:
python20 -
语义分析
在未使用
global的情况下:pythondef func(): x = 20解释器会将
x视为局部变量。使用
global后:pythondef func(): global x x = 20表示:
在当前函数中,
x的绑定操作直接作用于全局命名空间。 -
特性总结
- 可在函数内部修改全局变量
- 可在函数内部创建全局变量
- 直接影响模块级命名空间
- 使用不当可能导致程序状态难以维护
-
创建全局变量示例
pythondef func(): global y y = 100 func() print(y) # 100
4. nonlocal 关键字
-
定义
nonlocal用于在嵌套函数中声明变量来自外层函数作用域(Enclosing),并允许对其进行修改。 -
基本示例
pythondef outer(): x = 10 def inner(): nonlocal x x = 20 inner() print(x) outer()输出:
python20 -
语义分析
若不使用
nonlocal:pythondef inner(): x = 20则会在
inner内部创建新的局部变量x。使用
nonlocal后:pythondef inner(): nonlocal x x = 20表示:
将
x绑定到最近一层外部函数中的变量,并对其进行修改。 -
查找机制
nonlocal的查找路径为:python当前函数 → 外层函数 → 再外层函数 → ......其行为特点:
- 逐层向上查找
- 查找到第一个匹配变量即停止
- 若未找到则抛出语法错误
- 不会进入全局作用域
-
使用限制
- 必须存在对应的外层函数变量
- 只能用于嵌套函数结构
- 不能用于全局变量
-
错误示例
pythonx = 10 def func(): nonlocal x # SyntaxError错误信息:
pythonSyntaxError: no binding for nonlocal 'x' found
5. 对比分析
| 维度 | global | nonlocal |
|---|---|---|
| 作用范围 | 全局作用域 | 外层函数作用域 |
| 查找方式 | 直接作用于全局 | 逐层向上查找 |
| 是否必须存在 | 否 | 是 |
| 是否可作用于全局变量 | 是 | 否 |
| 使用位置 | 任意函数 | 嵌套函数内部 |
6. 典型案例分析
-
global行为示例pythonx = 0 def outer(): x = 1 def inner(): global x x = 100 inner() print("outer:", x) outer() print("global:", x)输出:
pythonouter: 1 global: 100说明:
inner修改的是全局变量- 不影响
outer中的局部变量
-
nonlocal行为示例pythondef outer(): x = 1 def inner(): nonlocal x x = 100 inner() print("outer:", x) outer()输出:
pythonouter: 100说明:
- 修改的是外层函数中的变量
-
多层嵌套示例
pythondef f1(): x = 1 def f2(): x = 2 def f3(): nonlocal x x = 3 f3() print("f2:", x) f2() print("f1:", x) f1()输出:
pythonf2: 3 f1: 1说明:
nonlocal只作用于最近一层外部函数
7. 常见误区
-
误区一:
nonlocal可以修改全局变量错误。
nonlocal不会查找到全局作用域。 -
误区二:赋值会自动修改外部变量
错误。 赋值默认在局部作用域创建新变量。
-
误区三:
global与nonlocal可以混用错误。 同一变量不能同时声明为
global与nonlocal。
8. 应用场景
-
global的使用场景- 全局配置管理
- 跨函数共享状态
(但应尽量减少使用,以降低耦合)
-
nonlocal的使用场景- 闭包(closure)
- 状态保持
- 计数器实现
-
示例:闭包计数器
pythondef counter(): count = 0 def inc(): nonlocal count count += 1 return count return inc
9. 本质总结
-
机制层面
global:将变量绑定到全局命名空间nonlocal:将变量绑定到外层函数命名空间
-
行为层面
- 默认赋值行为:创建局部变量
- 显式声明:改变绑定作用域
核心要点
- Python 中变量是"名称到对象"的绑定
- 赋值默认在局部作用域创建变量
global用于修改全局变量nonlocal用于修改外层函数变量
global用于跨越函数作用域修改全局绑定,nonlocal用于在嵌套函数中修改外层函数绑定。