
Python 为什么自动生成 .pyc 文件
Python 解释器在首次导入模块时,会将 .py 源码编译为字节码并缓存为 .pyc 文件,目的是避免重复编译、加快后续导入速度。这个过程由 import 触发,不是运行脚本(如 python main.py)时默认发生的——除非该脚本被当作模块被其他文件 import。
生成位置取决于 Python 版本:
• Python 3.2+ 使用 __pycache__ 目录,文件名形如 module.cpython-311.pyc;
• Python 2 或手动启用 -B 时可能直接生成同目录下的 module.pyc。
-
.pyc文件不包含源码,只含字节码 + 部分元数据(如源文件路径、时间戳、Python 版本标识) - 即使源码被删,只要
.pyc有效且未过期,import仍可成功(但 traceback 会显示原.py路径) - 若解释器无法写入
__pycache__(权限不足、只读文件系统),则跳过缓存,每次重新编译
.pyc 文件什么时候失效
Python 不依赖文件修改时间做简单比对,而是通过「源码文件的最后修改时间 + 大小」与 .pyc 头部存储的值比对。一旦不匹配,就判定为过期,丢弃旧 .pyc 并重建。
- 修改
.py文件内容后,下次import必然触发重编译 - 用
touch仅更新时间戳、或用编辑器保存空修改,也会导致校验失败 - 跨平台复制
.pyc通常失效:不同系统下文件大小/时间精度可能不同;更关键的是,.pyc头部硬编码了 Python 版本和 ABI 标签(如cpython-311),版本不一致直接拒绝加载 - 使用
compileall手动生成时,若指定-f强制覆盖,或-l不递归子包,容易遗漏部分模块,造成混合新旧缓存
如何控制 .pyc 的生成行为
有多个层级可干预,优先级从高到低:启动参数 > 环境变量 > 运行时设置。
- 启动时加
-B:完全禁止生成.pyc(包括__pycache__) - 设环境变量
PYTHONPYCACHEPREFIX=/tmp/pycache:把所有缓存统一移到外部路径,避免污染项目目录(Python 3.8+) - 设
PYTHONNOUSERSITE=1不影响.pyc,但设PYTHONDONTWRITEBYTECODE=1效果等同于-B - 运行时调用
sys.dont_write_bytecode = True可动态关闭当前解释器实例的写入,但无法影响已导入模块的缓存行为 - 注意:
py_compile.compile()和compileall.compile_dir()仍会生成,它们绕过解释器的自动机制
调试 .pyc 相关问题的实用技巧
当遇到 ImportError、奇怪的 ModuleNotFoundError,或怀疑缓存污染时,别急着删整个 __pycache__ —— 先确认是否真由 .pyc 引起。
注意:请在linux环境下测试或生产使用 青鸟内测是一个移动应用分发系统,支持安卓苹果应用上传与下载,并且还能快捷封装网址为应用。应用内测分发:一键上传APP应用包,自动生成下载链接和二维码,方便用户内测下载。应用封装:一键即可生成app,无需写代码,可视化编辑、 直接拖拽组件制作页面的高效平台。工具箱:安卓证书生成、提取UDID、Plist文件在线制作、IOS封装、APP图标在线制作APP分发:
立即学习“Python免费学习笔记(深入)”;
- 用
python -v -c "import mymodule"查看实际加载的是.py还是.pyc,以及路径 - 检查
.pyc头部:用xxd -l 24 mymodule.cpython-311.pyc看前几个字节,验证 ABI 标签和时间戳字段 - 对比源文件修改时间:
stat -c "%y %s" mymodule.py与.pyc头部记录是否一致 - 误删
.py后只剩.pyc?可用uncompyle6(非官方)反编译查看逻辑,但无法还原注释和原始变量名
真正麻烦的不是生成或删除,而是多人协作时混用不同 Python 小版本(如 3.11.2 vs 3.11.9)导致 .pyc 被静默忽略——此时 import 看似正常,实则每次都重新编译,性能下降却不报错。









