用 PyInstaller 打包一个 Python GUI 程序,想要”启动不弹 CMD 黑框、也不打成单个大文件”,一条命令搞定:
pyinstaller -w -D main.py
参数解释
-w(或 --noconsole):不开控制台窗口。适合 Tkinter、PyQt、PySide、wxPython 之类的 GUI。
-D(或 --onedir):文件夹形式打包。产物结构:
dist/
└── main/
├── main.exe
├── python3x.dll
└── ...(依赖 dll、pyd、资源)
跟 -F 单文件相比,-D 启动快、崩溃少、易调试,就是需要发一整个文件夹。
加图标
pyinstaller -w -D -i app.ico main.py
.ico 文件建议 256×256 或多尺寸 ico。
常见错误组合
GUI 忘了 -w:
pyinstaller -D main.py # 会弹黑色 CMD 窗口
GUI 只想单文件反而用了 -F -w:
pyinstaller -F -w main.py
能跑,但每次启动都要把打包体解压到临时目录,启动慢;sys._MEIPASS 拿资源要处理路径。
用 spec 文件更可控
第一次 pyinstaller 会生成 main.spec,之后修改这个文件重新构建:
pyinstaller main.spec
spec 里控制”无 CMD”的字段:
exe = EXE(
pyz,
a.scripts,
name='main',
console=False, # 无 CMD 窗口
icon='app.ico',
...
)
有 -w -D 起步足够,需要精细控制 hidden imports、数据文件、加签名时再上 spec。
加静态资源
程序里读了 templates/、assets/ 之类的目录,-D 只会打二进制,不带资源,运行时找不到。加 --add-data:
Windows(分隔符 ;):
pyinstaller -w -D main.py ^
--add-data "templates;templates" ^
--add-data "assets;assets"
macOS / Linux(分隔符 :):
pyinstaller -w -D main.py \
--add-data "templates:templates" \
--add-data "assets:assets"
代码里读资源要用 PyInstaller 兼容路径:
import sys, os
def resource_path(rel):
base = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base, rel)
with open(resource_path("templates/index.html")) as f:
...
找不到某个包
装了包但打包运行时抛 ModuleNotFoundError——PyInstaller 静态分析漏了动态导入。补 hidden-import:
pyinstaller -w -D main.py --hidden-import=some_dynamic_module
大量子模块可以直接 collect-all:
pyinstaller -w -D main.py --collect-all fastapi --collect-all uvicorn
一句话总结
pyinstaller -w -D main.py 是 GUI 程序打包最省心的一条命令。资源要 --add-data、动态导入要 --hidden-import 或 --collect-all。
