核心方案:Nuitka(主程序编译)+ 轻量配置(保留插件动态加载);备选:PyInstaller深度优化。
前置准备:精简环境
# 生成最小依赖清单 pipreqs . --encoding=utf8 --force # 卸载冗余包 pip uninstall -y pytest black isort
方案一:Nuitka(体积最小+性能最优,推荐)
1. 安装依赖
pip install nuitka==1.8.6 pyqt6==6.4.2 # 安装C++编译工具(Visual Studio Build Tools或MinGW64)
2. 打包命令(项目结构:main.py + plugins/ 插件目录)
nuitka ^ --onefile ^ # 单个EXE --windows-disable-console ^# 隐藏控制台 --windows-icon-from-ico=icon.ico ^ # 程序图标 --enable-plugin=pyqt6 ^ # 适配PyQt6 --nofollow-import-to=plugins ^ # 不编译插件(保留.py) --lto=yes ^ # 链接优化 --strip ^ # 剥离调试信息 --mingw64 ^ # MinGW编译(体积更小) main.py
3. 插件加载核心代码
import sys
import os
import importlib.util
def get_plugin_path():
# 处理打包后的路径
if hasattr(sys, 'frozen'):
base_path = os.path.dirname(sys.executable)
else:
base_path = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base_path, "plugins")
# 加载插件
def load_plugin(plugin_name):
plugin_path = get_plugin_path()
plugin_file = os.path.join(plugin_path, f"{plugin_name}.py")
spec = importlib.util.spec_from_file_location(plugin_name, plugin_file)
plugin = importlib.util.module_from_spec(spec)
spec.loader.exec_module(plugin)
return plugin
# 调用示例
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QMainWindow()
plugin1 = load_plugin("plugin1")
plugin1.run(window)
window.show()
sys.exit(app.exec())
4. 体积优化技巧
- 剔除PyQt6冗余模块:
--nofollow-import-to=PyQt6.QtWebEngine,PyQt6.QtMultimedia; - UPX压缩:
upx --best --lzma dist/main.exe。
方案二:PyInstaller(极简上手,体积次之)
1. 安装依赖
pip install pyinstaller==6.3.0 pyqt6==6.4.2
2. 打包命令
pyinstaller ^ -F ^ # 单文件 -w ^ # 隐藏控制台 -i icon.ico ^ # 图标 --exclude-module=PyQt6.QtWebEngine ^ # 剔除冗余模块 --upx-dir=./upx ^ # UPX压缩 main.py
分发说明
将EXE与plugins文件夹(含.py插件)放在同一目录,若需兼容老系统,附带VC_redist.x64.exe。
测试数据对比
| 方案 | 未压缩体积 | UPX压缩后体积 | 启动时间 |
|---|---|---|---|
| Nuitka | 18MB | 12MB | 0.3秒 |
| PyInstaller | 30MB | 20MB | 0.8秒 |
小竹工具箱