Python 全局变量使用
📚 Python 全局变量使用学习笔记
适用场景:模块级配置、缓存模型、单例状态管理等
核心原则:理解“变量绑定”与“对象修改”的区别
一、全局变量的定义
在模块顶层(函数外)定义的变量就是全局变量:
my_global = "hello"
config = {"debug": True}
cache = {}
这些变量在整个模块中都可访问。
二、在函数中使用全局变量的三种情况
情况 | 是否需要 global | 示例 | 说明 |
---|---|---|---|
✅ 1. 只读访问 | ❌ 不需要 | print(my_global) | 可直接读取 |
✅ 2. 修改可变对象内容 | ❌ 不需要 | cache["key"] = value config.update(...) | 修改的是对象内部 |
❌ 3. 重新赋值变量 | ✅ 必须加 global | my_global = "new" | 否则变成局部变量 |
三、关键规则总结
🔑 规则 1:赋值(=
)即局部
只要你在函数内对变量使用了
=
,Python 就认为它是局部变量,除非声明global
。
x = 10def bad():x = 20 # ❌ 错误:x 被当作局部变量,但未声明 global
✅ 正确写法:
def good():global xx = 20 # ✅ 修改全局 x
🔑 规则 2:修改可变对象内容,不需要 global
如果变量指向的是可变对象(如 list
, dict
, set
),修改其内容不需要 global
:
cache = {}
config = {"model": None}def load():cache["model1"] = "loaded" # ✅ 可以config["model"] = "bert-base" # ✅ 可以cache.update({"model2": "ok"}) # ✅ 可以
👉 原因:你没有改变 cache
这个变量的指向,只是通过它修改了对象内部。
🔑 规则 3:重新绑定变量必须用 global
data = [1, 2, 3]def reset():data = [4, 5, 6] # ❌ 错误:创建了局部变量 data
✅ 正确:
def reset():global datadata = [4, 5, 6] # ✅ 修改全局 data
四、常见误区与陷阱
❌ 误区 1:以为“定义过就不需要 global”
即使变量在外部定义了,函数内赋值仍需
global
,否则是局部变量。
❌ 误区 2:混合读取和赋值导致 UnboundLocalError
x = 10def foo():print(x) # ❌ 报错!x = 20
👉 原因:Python 看到 x = 20
→ 认为 x
是局部变量 → 但 print(x)
在赋值前使用 → 报错
五、global
vs nonlocal
对比
关键字 | 作用 | 使用场景 |
---|---|---|
global | 修改模块级全局变量 | x = ... 在函数外定义 |
nonlocal | 修改外层函数的局部变量 | 闭包中修改 enclosing 作用域 |
x = "global"def outer():x = "enclosing"def inner():global x # 修改 global 的 x# nonlocal x # 修改 outer 的 xx = "changed"inner()print(x) # 如果用 nonlocal → "changed";用 global → 不影响 outer 的 x
六、最佳实践建议
✅ 推荐做法:
- 避免滥用全局变量,优先使用函数参数或类封装。
- 模块级状态统一管理,如创建
model_manager.py
集中加载。 - 只读全局配置:用大写命名,如
CONFIG = {...}
。 - 可变全局状态:用
dict
或list
,通过方法修改内容,避免频繁global
。 - 启动时预加载:如模型、配置,在
lifespan
中同步加载即可。
✅ 示例:
_MODELS = {}def load_model(name, path):global _MODELS # 只在需要重新赋值 _MODELS 本身时才用model = load_from_path(path)_MODELS[name] = model # ✅ 修改 dict 内容,不需要 globaldef get_model(name):return _MODELS[name] # ✅ 只读,不需要 global
七、一句话口诀 🎯
🔔 “读不用 global,改内容也不用;只有赋值=,才需要 global。”
八、练习题(自测)
counter = 0
history = []def step():counter += 1 # 1. 会报错吗?history.append("step") # 2. 能成功吗?def reset():global countercounter = 0 # 3. 为什么这里要 global?history.clear() # 4. 这里需要 global 吗?
✅ 答案:
- ❌ 会报错(UnboundLocalError),因为
+=
是赋值 - ✅ 成功,修改 list 内容
- ✅ 因为
counter = 0
是重新绑定变量 - ❌ 不需要,
clear()
是修改对象内容
✅ 总结
操作 | 是否需要 global |
---|---|
print(x) | ❌ |
my_dict[key] = value | ❌ |
my_list.append(x) | ❌ |
x = ... | ✅ |
x += 1 | ✅(等价于 x = x + 1 ) |