根本原因是pyinstaller默认全量打包site-packages中所有模块,包括未使用的numpy、pandas等大型依赖及python解释器;需结合虚拟环境隔离、spec文件excludes精准排除、upx压缩c扩展及源头替换轻量依赖来综合瘦身。

为什么 PyInstaller 打包出来的 exe 总是特别大?
根本原因不是 Python 本身,而是 PyInstaller 默认把整个 site-packages 里所有可能用到的模块(包括你没 import 的)都打包进去了,尤其像 numpy、pandas、matplotlib 这类带 C 扩展的库,动辄几十 MB。再加上默认启用 UPX 压缩(如果装了)但不生效,或者用了但没配对——结果就是“看着压缩了,实际解压后还是那么大”。
--exclude-module 和 --hidden-import 必须配合用
光靠 --exclude-module 很容易误删依赖,导致运行时报 ModuleNotFoundError;但只加 --hidden-import 又会让没用的模块照常打进包里。关键是要先跑一次无排除的打包,再用 pyinstaller --debug=all 或直接运行生成的 exe 查日志,看它动态加载了哪些模块,再针对性排除。
-
--exclude-module=tkinter:GUI 不用时必须排除,它会拖入整个 Tcl/Tk 运行时(+15MB) -
--exclude-module=matplotlib:哪怕只用了plt.plot,默认也会打包全部后端和字体,排除后按需加--hidden-import=matplotlib.backends.backend_agg - 避免写
--exclude-module=numpy.core._multiarray_umath这种底层模块名——PyInstaller 识别不了,得排除顶层包
用 --onefile 还是 --onedir?选错反而更慢
--onefile 看似“干净”,但每次启动都要解压全部资源到临时目录(Windows 下是 %TEMP%/_MEIXXXXXX),首次启动卡顿明显,且杀毒软件常误报;--onedir 虽然多一个文件夹,但启动快、调试方便、更新也只需替换单个 .pyc 或 DLL。真正减体积的关键不在这个开关,而在精简依赖。
- 用
--onefile时务必加--upx-exclude=vcruntime140.dll——否则 UPX 会破坏 MSVC 运行时,导致黑窗闪退 -
--onedir下可手动删掉base_library.zip里没用的 .pyc(比如测试用的pytest模块),但别删_pyinstaller_hooks_contrib相关内容 - 如果程序要读取同目录下配置文件或图片,
--onedir更安全,--onefile需用sys._MEIPASS定位资源路径
UPX 真的有用吗?怎么避免踩坑
UPX 对纯 Python 字节码效果有限(通常只压 10–20%),但对 C 扩展 DLL(如 _multiarray_umath.cp39-win_amd64.pyd)压缩率可达 50%+。前提是 UPX 版本得匹配 Python 编译器版本(MSVC 2019 编译的 pyd 不能用 UPX 3.94 压,得用 4.0+)。
- 先确认 UPX 可用:
upx --version,再试压一个已知 DLL:upx -t your_module.pyd - 加参数时用
--upx --upx-exclude=python39.dll --upx-exclude=VCRUNTIME140.dll,这两者不能压 - 某些防病毒软件会拦截 UPX 压缩后的文件,上线前务必在目标环境实测启动
最省事的体积控制方式,其实是换依赖:用 ultralytics 替代 torchvision、用 orjson 替代 json、避免引入 scipy(除非真需要 FFT 或稀疏矩阵)。打包只是最后一环,源头精简才最有效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











