Python打包exe文件

文章导读
搜「Python打包exe文件」的人,卡点通常不在代码本身,而在打包之后就乱了:命令跑完了,dist 目录里有个 exe,双击却闪退;或者换台没有 Python 的电脑就报缺模块;再或者杀毒软件直接把它当可疑文件拦掉。要立刻得到的结论是:先用 PyInstaller 打出一个最小的单文件 exe,在干净的 Windows 环境里跑一次,看它到底报什么错,再决定是补 hidden import、加数
📋 目录
  1. A 打包exe文件:先把能核对的事实摆清楚
  2. B 打包exe文件最容易搞错的一点
  3. C 打包exe文件:一个照着就能做完的做法
  4. D 打包exe文件:怎么验证结果对不对
A A

搜「Python打包exe文件」的人,卡点通常不在代码本身,而在打包之后就乱了:命令跑完了,dist 目录里有个 exe,双击却闪退;或者换台没有 Python 的电脑就报缺模块;再或者杀毒软件直接把它当可疑文件拦掉。要立刻得到的结论是:先用 PyInstaller 打出一个最小的单文件 exe,在干净的 Windows 环境里跑一次,看它到底报什么错,再决定是补 hidden import、加数据文件,还是改成目录模式。版本、参数默认值这类会变的内容,以本机 pyinstaller --version 和官方文档对应版本页为准。

打包 exe 的判断顺序是:先确认入口脚本能在本机用 python 直接跑通,再用 PyInstaller 生成,最后在没有 Python 的机器上验证。多数“打包失败”其实是运行时缺模块或缺数据文件,而不是打包命令写错。先打单文件方便分发,但排错阶段建议用 -D 目录模式看完整报错,定位后再改 --onefile。exe 只能在对应架构的 Windows 上跑,跨平台需要各自打包。

打包exe文件:先把能核对的事实摆清楚

先把对象和前提固定下来,避免在错误层面上排查:

  • 入口脚本:明确哪个 .py 是启动文件,例如 main.py;它必须能在本机用 python main.py 正常跑完主要流程。
  • 解释器环境:python -V 输出的版本,以及 pip show pyinstaller 显示的 PyInstaller 版本。这两条是可核对的事实,不同组合下参数行为会有差异。
  • 产物位置:PyInstaller 默认在脚本同目录生成 build/、dist/ 和 xxx.spec。exe 在 dist/ 下;build/ 里是中间文件和 warn 文件。
  • 日志字段:build/<name>/warn-<name>.txt 会记录缺失模块的候选清单,这是判断“缺了什么”的第一手材料。

可核对的现象通常有三类:命令行里出现 ModuleNotFoundError、双击后窗口一闪而过、exe 在开发机上正常但在其他机器上报错。前两类看终端输出和 warn 文件即可,第三类必须换机验证。当前未联网检索,具体版本的默认参数请以本机 pyinstaller --help 为准。

打包exe文件最容易搞错的一点

最常见的误解是:只要打包命令执行成功,exe 就能在任意机器上跑。实际分界线在于“打包成功”和“运行成功”是两件事。PyInstaller 在构建阶段只做静态扫描,动态导入(importlib、插件式加载、__import__ 拼字符串)不会被自动收进去,构建照样显示完成。

一个能把两种情况区分开的检查动作:把 dist/ 里的 exe 复制到一台没有安装 Python、且没有你的项目依赖的 Windows 机器上,用命令行启动它——在资源管理器地址栏输入 cmd 回车,再执行:

cd /d D:\test\dist
.\main.exe

如果窗口里刷出 ModuleNotFoundError: No module named 'xxx',问题在依赖收集,需要用 --hidden-import 补;如果报的是找不到某个数据文件(例如配置、模板、字体),问题在数据文件没被打进去,要用 --add-data 或 spec 文件的 datas 配置。若在开发机上双击正常、换机才失败,几乎可以排除命令拼写问题。--onefile 模式下报错窗口一闪而过,看不到信息,这正是排错阶段建议先用目录模式的原因。

打包exe文件:一个照着就能做完的做法

下面这条路径按顺序执行,每一步都写明该看到什么。先装工具:

Python打包exe文件
python -m pip install --upgrade pyinstaller
pyinstaller --version

第二条命令应打印出版本号,例如 6.x 形式的三段数字;没有输出或报“不是内部或外部命令”,说明没装进当前解释器,检查是不是在虚拟环境里执行。

第一步先打目录模式,方便看报错:

pyinstaller --noconfirm --clean --name main -D main.py

--noconfirm 跳过覆盖确认,--clean 清缓存,-D 是目录模式。执行末尾应看到 Build complete!,并且 dist/main/ 下出现 main.exe 和一堆依赖文件。在命令行里运行 dist\main\main.exe,确认功能正常。

第二步补缺失依赖。假设日志提示缺少 requests:

pyinstaller --noconfirm --clean --name main -D --hidden-import requests main.py

第三步加入数据文件。Windows 下 --add-data 的分隔符是分号,源路径在前、包内路径在后:

Python打包exe文件
pyinstaller --noconfirm --clean --name main -D --add-data "config;config" --add-data "templates;templates" main.py

代码里读取这些资源要用 sys._MEIPASS 判断是否处于打包环境,否则开发时能跑、打包后找不到路径。

第四步功能确认后再改单文件分发:

pyinstaller --noconfirm --clean --name main -F --hidden-import requests --add-data "config;config" main.py

-F 即 --onefile,产物是单个 dist/main.exe。注意单文件模式每次启动会先解压到临时目录,启动比目录模式慢,这是机制决定的,不是打包错误。

容易踩的坑:--add-data 在 Windows 用分号、在 Linux 和 macOS 用冒号,照抄网上命令时经常在这一步失败;另外路径里带空格或中文时,务必用引号包住,并尽量在纯英文路径下构建。

打包exe文件:怎么验证结果对不对

验证分三层,逐层过:

  1. 构建层:命令结束后确认 dist/ 下有目标 exe,build/<name>/warn-<name>.txt 存在。打开 warn 文件看有没有你实际用到的包名,有就补 hidden import 后重打。
  2. 运行层:在命令行而非双击启动 exe,正常结果是没有 Traceback、程序按预期完成主要流程、退出码为 0。在 cmd 里执行完立刻输入 echo %errorlevel%,输出 0 表示正常退出;非 0 说明程序内部报错,回到终端输出看堆栈。
  3. 分发层:找一台没有 Python、没有项目依赖的 Windows 机器,把 exe 拷过去跑一遍;带数据文件的,重点检查读取配置、模板的功能是否正常。

判断标准很直接:三层都通过才算可用;任何一层报缺模块或缺文件,都回到上一节的命令补参数重打,而不是去改业务代码。如果验证时发现杀毒软件拦截,这属于误报处理范畴,建议向对应厂商提交样本,不要靠改文件名绕过。