PyInstaller能否仅打包Python二进制,首次运行时通过pip装依赖减包体积?
延迟依赖安装以缩小Python应用分发体积
问题背景
使用PyInstaller打包基于pywebview、TensorFlow构建的Python应用时,生成的可执行文件体积远超预期,原因是PyInstaller默认会打包所有依赖库。希望实现仅打包Python二进制核心文件,在应用首次运行时通过pip install自动安装所需依赖,以此缩小分发包体积。
此前尝试通过直接调用pip模块实现延迟安装,代码如下:
import sys, io buffer = io.StringIO() sys.stdout = sys.stderr = buffer import pip pip.main(['install', 'numpy']) import webview webview.create_window('Hello world', 'https://pywebview.flowrl.com/') webview.start()
但运行打包后的demo.exe时出现错误:
Traceback (most recent call last): File "demo.py", line 7, in <module> File "pip\__init__.py", line 13, in main File "pip\_internal\utils\entrypoints.py", line 43, in _wrapper File "pip\_internal\cli\main.py", line 68, in main File "pip\_internal\commands\__init__.py", line 114, in create_command File "importlib\__init__.py", line 127, in import_module File "<frozen importlib._bootstrap>", line 1014, in _gcd_import File "<frozen importlib._bootstrap>", line 991, in _find_and_load File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked ModuleNotFoundError: No module named 'pip._internal.commands.install'
错误原因
pip.main()是已废弃的旧API,pip官方不推荐在代码中直接调用内部模块- PyInstaller默认不会打包pip的内部命令模块,导致运行时找不到
pip._internal.commands.install
解决方案
一、修复PyInstaller打包时的延迟安装逻辑
放弃直接调用pip内部API,改用subprocess调用系统级pip,这种方式更稳定且无需额外打包pip内部模块:
import subprocess import sys # 调用当前环境的pip安装指定依赖,可添加版本号确保兼容性 subprocess.check_call( [sys.executable, "-m", "pip", "install", "numpy==1.26.0", "pywebview==4.0.0", "tensorflow==2.15.0"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) import webview webview.create_window('Hello world', 'https://pywebview.flowrl.com/') webview.start()
打包时只需确保不包含目标依赖,可通过--exclude-module参数明确排除:
pyinstaller --onefile --exclude-module=numpy --exclude-module=pywebview --exclude-module=tensorflow demo.py
二、PyInstaller轻量化打包优化
如果想进一步缩小基础包体积,可结合以下参数:
--clean:清理打包缓存--noconsole:针对GUI应用,隐藏命令行窗口--strip:剥离二进制文件中的调试信息(仅适用于类Unix系统)
三、替代打包工具
1. cx_Freeze
配置仅打包Python解释器和业务代码,排除所有大依赖,在代码中处理延迟安装:
编写setup.py配置文件:
import sys from cx_Freeze import setup, Executable # 针对Windows GUI应用设置base base = 'Win32GUI' if sys.platform == 'win32' else None executables = [Executable('demo.py', base=base)] setup( name='LightweightApp', version='1.0', description='App with delayed dependency installation', executables=executables, options={ 'build_exe': { 'excludes': ['numpy', 'pywebview', 'tensorflow'], 'optimize': 2 # 优化字节码 } } )
执行打包命令:
python setup.py build
2. PyOxidizer
支持构建最小化Python运行时,可配置首次启动时自动从PyPI下载安装依赖。核心配置示例(pyoxidizer.toml):
[project] name = "myapp" version = "0.1.0" [[python_packaging.pip_install]] packages = ["numpy==1.26.0", "pywebview==4.0.0", "tensorflow==2.15.0"] install_mode = "after_launch" # 延迟安装到启动后 [[python_packaging.entry_point]] type = "console_script" name = "myapp" module = "demo" function = "main"
执行打包:
pyoxidizer build
3. Nuitka
将Python代码编译为C语言二进制,可通过参数排除依赖,实现延迟安装:
打包命令:
nuitka --standalone --nofollow-imports=numpy,pywebview,tensorflow --windows-disable-console demo.py
代码中同样使用subprocess调用pip安装依赖。
注意事项
- 首次运行需确保设备联网,建议在应用启动时添加联网提示
- 指定依赖版本可避免不同环境下的兼容性问题
- 延迟安装会增加首次启动时间,需在用户体验和包体积之间做平衡
内容的提问来源于stack exchange,提问作者link89
相关产品推荐
相关产品推荐

