python的.pyc缓存更新依赖magic number和source_hash双校验,任一不匹配即重编译;常见失效原因包括文件系统只读、多环境共用缓存、ide保存延迟、python -b启动等,优先检查__pycache__目录是否可写。

Python 的 .pyc 缓存不会仅靠文件修改时间(mtime)决定是否更新,改完代码却没生效,大概率是缓存校验机制“没认出变化”或“认错了”。这不是 bug,而是设计使然——它依赖更严格的双校验逻辑。
Python 怎么判断 .pyc 是否该重编译
Python 不看 touch 后的时间戳,而是检查两个关键元数据:
-
magic number:嵌入在.pyc头部,标识 Python 主次版本(如 3.12 →3420)。跨小版本升级(3.11 → 3.12)必然失效 -
source_hash:CPython 3.7+ 使用 8 字节哈希,基于源码内容 + mtime + size 计算。只要源码字节变了,hash 就该变
只有两者全部匹配,才复用 .pyc;任一不匹配,就丢弃旧缓存、重新编译。但注意:极小概率下,不同源码内容可能产生相同 source_hash(哈希碰撞),导致旧 .pyc 被误用——这就是“明明改了却没生效”的隐蔽原因。
常见导致缓存未更新的实操场景
这些情况会让校验逻辑“失灵”或跳过更新:
- 文件系统只读(如容器
/app挂载为ro):Python 静默跳过写.pyc,每次import都现场编译,但用户无感知 - 多环境共用同一代码目录:conda、pyenv、系统 Python 同时写同一个
__pycache__,权限冲突或覆盖导致缓存残留 - IDE 自动保存延迟 + 快速运行:编辑后立刻
python main.py,而.pyc还没写完,加载的是上一版缓存 - 使用
python -B启动:禁用生成新.pyc,但**不删除已有缓存**,旧.pyc仍会被加载
如何快速验证和强制刷新缓存
别猜,直接动手确认:
- 查缓存路径:
import importlib.util; print(importlib.util.cache_from_source('utils.py')),看对应.pyc是否存在、时间戳是否旧于.py - 手动删缓存:
rm -rf __pycache__/(Linux/macOS)或rmdir /s __pycache__(Windows),再重启 Python 进程(不是仅Ctrl+C,要关掉解释器) - 启动时禁用缓存:
python -B script.py(临时调试)或设环境变量PYTHONDONTWRITEBYTECODE=1(当前 shell 会话生效) - 预编译并强制覆盖:
python -m compileall -f mypackage/,-f确保重写所有.pyc
真正容易被忽略的是:缓存是否可写,比“有没有改代码”更优先影响行为。如果 __pycache__ 目录不可写,Python 就根本不会尝试更新它——你看到的“没生效”,其实是它压根没打算生效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











