杰瑞科技汇

Python PyInstaller打包体积过大如何解决?

下面我将从 原因分析通用优化方法高级技巧替代方案 四个方面,为你提供一套完整的解决方案。

Python PyInstaller打包体积过大如何解决?-图1
(图片来源网络,侵删)

问题根源分析:为什么 PyInstaller 打包的文件这么大?

我们要明白 PyInstaller 默认做了什么:

  1. 打包整个 Python 环境:PyInstaller 默认会分析你的代码,找到所有导入的模块,然后将这些模块连同 Python 解释器一起打包进去,如果你的项目依赖了很多第三方库(如 numpy, pandas, torch),体积自然会非常庞大。
  2. 包含不必要的文件:默认配置下,PyInstaller 可能会打包一些你用不到的动态链接库(.dll, .so)或数据文件。
  3. 未压缩或压缩率低:打包后的可执行文件本身就是一个压缩包,如果配置不当,压缩效果会很差。

通用优化方法(90% 的情况适用)

这些方法简单有效,应该首先尝试。

使用 --onefile 还是 --onedir

这是一个关键选择。

  • --onedir (默认): 生成一个文件夹,包含可执行文件和所有依赖的 .dll.pyd 文件。
    • 优点: 启动速度快,因为解压步骤少;更新单个依赖时无需重新打包整个程序。
    • 缺点: 需要分发一个文件夹,而不是单个文件。
  • --onefile: 生成一个单独的可执行文件,首次运行时,它会将自身解压到一个临时目录,然后执行。
    • 优点: 分发方便,只有一个文件。
    • 缺点: 启动速度稍慢(因为要解压);解压后的临时文件会留在用户电脑上(可以通过 --noupx 或清理代码处理)。

建议: 如果不追求极致的单文件分发,优先使用 --onedir,它的启动速度和性能优势明显,而且对于很多应用来说,一个文件夹也是可以接受的。

Python PyInstaller打包体积过大如何解决?-图2
(图片来源网络,侵删)

使用 --clean--noconfirm

  • --clean: 在每次打包前,先清理旧的 builddist 目录,这能确保没有旧文件残留,导致打包结果不准确。
  • --noconfirm: 覆盖输出目录而不提示。

最佳实践: 在每次打包时都加上这两个参数。

pyinstaller --clean --noconfirm your_script.py

排除不必要的模块和数据 (--exclude-module--add-data)

这是最有效的瘦身方法之一。

  • 排除模块: 如果你使用了某个库,但你的代码并没有用到它的全部功能,可以尝试排除。

    • matplotlib 会打包很多后端,如果你只用 Agg(无界面渲染),可以排除其他后端。
    • tkintertcl 库非常巨大,如果不用 GUI,可以尝试排除。
    # 排除 matplotlib 的 Qt 和 Tk 后端
    pyinstaller --exclude-module matplotlib.backends.qt4 \
                --exclude-module matplotlib.backends.qt5 \
                --exclude-module matplotlib.backends.tkagg \
                your_script.py
  • 添加数据文件: 如果你的程序需要读取图片、配置文件等,需要使用 --add-data,格式为 源路径:目标路径,路径用分号 (Windows) 或冒号 (Linux/macOS) 分隔。

    # 假设你的图片在 res/ 目录下,打包后希望存放在程序内的 res/ 目录
    pyinstaller --add-data "res;res" your_script.py

使用 UPX 压缩 (--upx-dir--noupx)

UPX 是一个可执行文件压缩工具,PyInstaller 可以用它来压缩最终的可执行文件和依赖库。

  • 安装 UPX: UPX 官网 下载并解压,将 upx.exe (Windows) 或 upx (Linux/macOS) 所在目录添加到系统 PATH 中。
  • 启用 UPX:
    pyinstaller --upx-dir "C:\path\to\upx" your_script.py
  • 禁用 UPX: 有时 UPX 会和某些杀毒软件冲突,或者导致启动失败,可以禁用它。
    pyinstaller --noupx your_script.py

高级优化技巧(针对顽固问题)

如果通用方法效果不佳,可以尝试以下进阶技巧。

分析依赖 (--analyze--log-level=INFO)

PyInstaller 2.1+ 版本内置了依赖分析器,可以更准确地找出真正需要的模块。

  • --analyze: 生成一个 .features 文件,详细列出了每个模块和它被引用的原因,可以帮助你找到不必要的依赖。
  • --log-level=INFO: 在控制台输出更详细的信息,可以看到哪些模块被包含或排除了。
pyinstaller --onefile --clean --noconfirm --log-level=INFO --analyze your_script.py

打包后,在 build/your_script/ 目录下会找到 your_script.specyour_script.analyze.json,里面包含详细的依赖分析。

手动编辑 .spec 文件

.spec 文件是 PyInstaller 的配置文件,通过修改它可以实现更精细的控制。

  • hiddenimports: PyInstaller 没能自动检测到某些动态导入的模块,可以手动添加。

    # your_script.spec
    a = Analysis(
        ['your_script.py'],
        ...
        hiddenimports=['some_module_that_was_not_detected'],
        ...
    )
  • excludes: 这是最强大的排错工具,将你确定用不到的模块名加入列表。

    # your_script.spec
    a = Analysis(
        ['your_script.py'],
        ...
        excludes=['matplotlib', 'PIL', 'tkinter'], # 强制排除这些库
        ...
    )

    你可以通过 pip list 查看所有已安装的库,然后逐一尝试排除,观察打包体积的变化。

  • binariesdatas: 手动添加或移除二进制文件和数据文件。

    # your_script.spec
    a = Analysis(
        ...
        binaries=[('path/to/your/custom.dll', '.')], # 添加一个特定的dll
        datas=[('config.json', '.')], # 添加数据文件
        ...
    )

使用虚拟环境

这是最重要、最基础的一步!

永远不要在你开发的全局 Python 环境中打包,创建一个干净的虚拟环境,只安装你的项目真正需要的依赖。

# 1. 创建虚拟环境
python -m venv myenv
# 2. 激活虚拟环境
# Windows:
myenv\Scripts\activate
# Linux/macOS:
source myenv/bin/activate
# 3. 只安装项目依赖,不要装 jupyter notebook, ipython 等开发工具
pip install -r requirements.txt
# 4. 在这个干净的环境中运行 PyInstaller
pyinstaller --onefile your_script.py

这样做可以避免把开发工具、测试框架等打包进去,能极大减小体积。

针对 numpy, pandas, scipy 等科学计算库的优化

这些库体积巨大,因为它们包含了大量的编译代码(C/C++/Fortran)。

  • 使用 --exclude-module: 尝试排除你不用的子模块。
    # 如果只用numpy的数组功能,可以尝试排除其子模块
    pyinstaller --exclude-module numpy.testing \
                --exclude-module numpy.distutils \
                --exclude-module numpy.f2py \
                your_script.py
  • 从源码编译: 这是一个更复杂但更有效的方法,在虚拟环境中,使用 pip install --no-binary :all: numpy 来从源码编译安装,这样 PyInstaller 只会打包你编译时用到的部分,但这需要你系统上有相应的编译工具链。

替代方案

PyInstaller 实在无法满足你的需求,可以考虑以下替代工具。

  1. Nuitka
    • 特点: 它不是一个打包工具,而是一个 Python 编译器,它将你的 Python 代码(包括 C 扩展)编译成一个真正的本地可执行文件(C++ 程序)。
    • 优点: 启动速度更快,运行性能更好,通常打包体积比 PyInstaller 更小、更干净。
    • 缺点: 编译过程非常耗时,兼容性需要测试。
    • 用法:
      # 首先用 PyInstaller 生成
分享:
扫描分享到社交APP
上一篇
下一篇