什么是全局作用域?
全局作用域 是指在 Python 程序的最外层定义的变量、函数、类等标识符所存在的“空间”,它的特点是:

- 生命周期:从程序开始执行时创建,直到整个程序运行结束才销毁。
- 可见性:默认情况下,程序内的任何地方(包括函数内部)都可以“访问”(读取)全局作用域中的变量。
- 定义位置:任何没有缩进,或者位于模块(
.py文件)最顶层的代码,都在全局作用域中。
一个简单的例子:
# 这里的 message 变量定义在全局作用域
message = "Hello, Global Scope!"
def greet():
# 在函数内部,我们可以直接访问全局变量 message
print(message)
# 调用函数
greet()
# 输出: Hello, Global Scope!
在这个例子中,message 就是一个全局变量,无论在 greet() 函数内部还是外部,我们都可以读取它的值。
关键问题:在函数内部修改全局变量
这是初学者最容易混淆的地方,记住一个核心原则:
在函数内部,如果你只是“读取”一个全局变量,可以直接使用,但如果你要“修改”一个全局变量,Python 会默认将其视为一个局部变量,除非你显式地声明它为全局变量。

只读访问 (可以)
global_var = 100
def read_global():
# 只读取,不修改
print(f"Inside function, global_var is: {global_var}")
read_global()
print(f"Outside function, global_var is: {global_var}")
# 输出:
# Inside function, global_var is: 100
# Outside function, global_var is: 100
修改访问 (会出错,除非使用 global 关键字)
错误示范:
下面的代码会抛出 UnboundLocalError,因为 Python 看到 global_var = global_var + 1 这行代码,认为你想要在函数内部创建一个名为 global_var 的局部变量,但在执行赋值操作之前,你尝试读取这个还不存在的局部变量,所以报错。
global_var = 100
def modify_global_wrong():
print(f"Before modification, global_var is: {global_var}") # 尝试读取
global_var = global_var + 1 # 尝试修改
print(f"After modification, global_var is: {global_var}")
modify_global_wrong()
# 输出:
# Before modification, global_var is: 100
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "<stdin>", line 2, in modify_global_wrong
# UnboundLocalError: local variable 'global_var' referenced before assignment
正确示范:使用 global 关键字
为了在函数内部修改全局变量,你必须使用 global 关键字来告诉 Python:“我要操作的这个 global_var 是全局作用域的那个,而不是要创建一个新的局部变量”。
global_var = 100
def modify_global_correct():
# 声明 global_var 是全局变量
global global_var
print(f"Before modification, global_var is: {global_var}")
global_var = global_var + 1 # 现在这是在修改全局变量
print(f"After modification, global_var is: {global_var}")
modify_global_correct()
print(f"Outside function, final global_var is: {global_var}")
# 输出:
# Before modification, global_var is: 100
# After modification, global_var is: 101
# Outside function, final global_var is: 101
global 关键字的详细用法
global 关键字用于在函数内部声明一个或多个变量为全局变量。
语法:
global variable_name1, variable_name2, ...
作用:
- 声明变量来源:告诉解释器,这个变量是定义在全局作用域的。
- 允许修改:允许你在函数内部对该变量进行赋值操作,从而修改全局变量的值。
- 创建新全局变量:如果全局作用域中不存在该变量,使用
global关键字并在函数中为其赋值,会创建一个新的全局变量。
示例:创建新全局变量
def create_new_global():
# 声明并创建一个新的全局变量 new_var
global new_var
new_var = "I am a new global variable!"
create_new_global()
# 现在可以在全局访问 new_var
print(new_var)
# 输出: I am a new global variable!
作用域的查找顺序(LEGB 规则)
理解了全局作用域,你还需要知道 Python 是如何查找一个变量的,Python 遵循 LEGB 规则,按顺序查找:
- L (Local):局部作用域,即函数内部。
- E (Enclosing):嵌套作用域,即嵌套函数的外层函数作用域。
- G (Global):全局作用域,即模块的最顶层。
- B (Built-in):内置作用域,即 Python 解释器内置的函数和变量(如
len(),print()等)。
图示:
B (Built-in)
^
|
G (Global) <-- my_module.py 的顶层
^
|
E (Enclosing) <-- 外层函数 outer_func()
^
|
L (Local) <-- 内层函数 inner_func()
例子:
# G: Global
global_var = "Global"
def outer_func():
# E: Enclosing
enclosing_var = "Enclosing"
def inner_func():
# L: Local
local_var = "Local"
# 按照 LEGB 顺序查找
print(local_var) # 找到 L
print(enclosing_var) # 找到 E
print(global_var) # 找到 G
print(len) # 找到 B (内置函数)
inner_func()
outer_func()
全局作用域的最佳实践
虽然全局变量很方便,但过度使用它们会带来很多问题,
- 代码难以维护:任何函数都可以修改全局变量,导致程序状态难以追踪。
- 命名冲突:在大型项目中,不同模块可能会不小心使用相同的全局变量名。
- 函数副作用:函数不再“纯净”,因为它会改变外部环境,使得测试和复用变得困难。
有以下几个最佳实践:
- 最小化全局变量的使用:只在真正需要在整个程序中共享状态时才使用全局变量。
- 使用
global关键字明确意图:当你确实需要在函数中修改全局变量时,务必使用global关键字,这向其他开发者清晰地表明了你的意图。 - 优先使用函数参数和返回值:这是更“函数式”、更安全的方式,函数通过接收参数来获取数据,通过返回值来输出结果,而不是直接修改外部变量。
好的实践 (通过参数和返回值):
def add_one(number):
# 不依赖任何全局变量,纯粹根据输入计算
return number + 1
count = 10
new_count = add_one(count) # 通过参数传递,通过返回值获取结果
print(new_count) # 输出: 11
print(count) # 原始变量没有被修改
什么时候使用全局变量是合理的?
- 配置常量:
API_KEY = "..."或DEBUG = True,这些值在整个程序中都是不变的。 - 程序状态管理:在一个简单的游戏中,
player_score可能是一个全局变量,由多个事件处理函数共同更新。 - 缓存:为了避免重复计算,将计算结果存储在一个全局变量中。
| 特性 | 描述 |
|---|---|
| 定义 | 程序最顶层定义的变量、函数等的作用域。 |
| 生命周期 | 从程序开始到结束。 |
| 访问 | 默认可在任何地方读取。 |
| 修改 | 在函数内修改必须使用 global 关键字声明。 |
| 查找规则 | 遵循 LEGB 规则:Local -> Enclosing -> Global -> Built-in。 |
| 最佳实践 | 谨慎使用,优先通过参数和返回值传递数据,以提高代码的可维护性和可测试性。 |
