load_fast 比 load_global 快2–5倍,因前者是栈帧索引直取,后者需模块字典哈希查找;局部变量提速由编译期决定,循环中将全局引用赋为局部变量可显著优化性能。

LOAD_FAST vs LOAD_GLOBAL:字节码层面的性能分水岭
Python 局部变量快,不是因为“栈比堆快”这种模糊说法,而是编译器在函数定义时就确定了每个局部变量在栈帧中的固定索引位置,运行时直接用 LOAD_FAST 指令按索引取值;而全局变量每次访问都得走 LOAD_GLOBAL,触发模块 __dict__ 的哈希查找——计算哈希、定位桶、比对键字符串,常数开销大得多。
你可以用 dis.dis(func) 验证:循环里写 math.sqrt(x) 会反复出现 LOAD_GLOBAL;改成 sqrt = math.sqrt 后再调用 sqrt(x),循环体里只剩 LOAD_FAST 和 CALL_FUNCTION。
- 局部变量提速是编译期决定的,不是运行时优化
-
LOAD_FAST是纯内存寻址,LOAD_GLOBAL是字典操作,实测高频访问下慢 2–5 倍 - 闭包变量走
LOAD_DEREF(cell 解引用),性能居中,比LOAD_GLOBAL快但不如LOAD_FAST
global 关键字不加速读取,只解决赋值作用域
加 global x 不会让 x 变快,反而可能拖慢:读取时仍走完整 LEGB 查找路径;写入时还多一次作用域绑定检查。它唯一作用是告诉解释器“这个赋值要落到全局作用域”,否则函数内一旦出现 x = ...,x 就被标记为局部变量,导致前面的 print(x) 报 UnboundLocalError。
- 只读全局变量?完全没必要加
global,纯属冗余 - 又读又写?优先考虑传参或缓存,而不是靠
global硬扛 - 首次在函数内赋值全局变量时,解释器会强制创建绑定,有额外初始化开销
高频循环里“拉进来”三行代码就能见效
在 for 循环或密集计算中反复访问全局配置、模块函数或大型对象引用时,把它们提到函数开头赋给局部变量,是最简单有效的提速手段。这不是微优化,而是绕过解释器底层瓶颈的直击方案。
比如:
CONFIG_TIMEOUT = 30
def fetch():
timeout = CONFIG_TIMEOUT # ← 这一行让后续所有 timeout 访问变快
for _ in range(1000000):
time.sleep(timeout) # 这里用的是 LOAD_FAST,不是 LOAD_GLOBAL
- 可变对象(如
list、dict)赋值给局部变量只是引用复制,无内存拷贝开销 - 避免在循环体内写
import math; math.sqrt(x),应提前绑定sqrt = math.sqrt - 跨模块访问如
utils.CONST比直接CONST多一层属性查找,也建议拉平
容易被忽略的退化场景:局部变量未必真“局部”
哪怕你写了 x = 1,如果函数里存在 exec()、eval()、global 或 nonlocal 声明,或者在赋值前就尝试读取同名变量(如先 print(x) 再 x = 1),CPython 编译器就会放弃局部优化,降级为 LOAD_GLOBAL 或更慢的动态查找路径。
- 作用域判断发生在编译期,不是运行时——别指望“条件分支里没执行赋值就安全”
- 使用
dis.dis()是唯一可靠方式,确认你写的“局部变量”确实生成了LOAD_FAST - 真正难处理的从来不是速度本身,而是你根本没意识到某个
LOAD_GLOBAL正卡在火焰图顶部
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











