跳转至

PyInstaller 命令行打包指南

本文介绍如何使用命令行把 Python 脚本打包为 EXE,包含命令解释、参数说明、示例和注意事项。

一、基本语法

pyinstaller [参数] 你的脚本.py
  • 打包前需先安装:pip install pyinstaller
  • 查看帮助:pyinstaller --help
  • 查看版本:pyinstaller --version

二、核心参数解释

2.1 打包模式(必选其一,默认 -D)

参数 全称 意义
-F --onefile 单文件模式:只生成一个 EXE,分发方便,但启动稍慢
-D --onedir 单目录模式:生成一个文件夹,启动快,便于排查问题(默认)

2.2 窗口模式(必选其一,默认 -c)

参数 全称 意义
-w --windowed / --noconsole 打包为无控制台窗口的 GUI 程序
-c --console 保留控制台窗口(CLI 命令行程序用,默认)

2.3 图标与名称

参数 意义
-i 图标.ico--icon 图标.ico 给 EXE 指定图标(必须是真正的 .ico 文件)
--name 名称 指定输出文件名,默认与脚本同名
--version-file 文件.txt 给 EXE 附加版本信息(右键属性可见)

2.4 附加资源与依赖

参数 意义
--add-data "源路径;目标目录" 打包脚本之外的文件(图片、配置文件等)。Windows 用 ; 分隔,Linux/macOS 用 :
--paths 目录 额外指定模块搜索路径(脚本依赖第三方库且不在默认位置时用),可多次使用
--hidden-import 模块名 强制打包某个模块(PyInstaller 分析不到时用,如动态 import)
--exclude-module 模块名 排除某个模块,减小体积

2.5 输出控制

参数 意义
--distpath 目录 指定 EXE 输出目录(默认 ./dist)
--specpath 目录 指定 .spec 配置文件输出目录
--workpath 目录 指定中间工作目录(默认 ./build)
--noconfirm 输出目录已有文件时直接覆盖,不弹询问
--clean 打包前清理上一次的缓存

三、常用示例

示例 1:打包 CLI 脚本(最简)

pyinstaller -F my_script.py

产物:dist/my_script.exe,双击在命令行中运行。

示例 2:打包 GUI 程序

pyinstaller -F -w my_gui.py

-w 去掉黑色控制台窗口,适合 tkinter / PyQt 等图形程序。

示例 3:GUI 程序 + 图标

pyinstaller -F -w -i my_icon.ico my_gui.py

示例 4:附带资源文件

pyinstaller -F -w --add-data "config.json;." --add-data "images;images" my_gui.py
  • config.json;.:把配置文件放进 EXE 的根目录
  • images;images:把整个文件夹打包为 images/ 子目录

示例 5:依赖第三方库的脚本

pyinstaller -F --paths "D:\envs\my_env\Lib\site-packages" my_script.py

示例 6:动态导入导致缺模块

pyinstaller -F --hidden-import pkg_resources my_script.py

示例 7:完整组合

pyinstaller -F -w -i app.ico --add-data "assets;assets" --noconfirm --clean app.py

四、注意事项

4.1 -w 与 stdin/stdout

依赖 input()print()sys.stdin 的脚本绝不能加 -w,否则打包后: - input() 直接抛 EOFError 崩溃 - 控制台输出全部不可见

判断标准:脚本在命令行里会读写控制台的,用 -c(即不加 -w);纯 GUI 交互的才用 -w

4.2 附加资源文件的读取路径

打包后 EXE 运行时,当前工作目录不一定是 EXE 所在目录,直接写相对路径(如 open("config.json"))可能找不到文件。应在代码中基于可执行文件位置解析路径:

1
2
3
4
5
6
7
8
9
import sys, os

def resource_path(relative):
    """兼容打包前后两种运行方式的路径解析"""
    base = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base, relative)

with open(resource_path("config.json"), encoding="utf-8") as f:
    data = f.read()

原理:-F 单文件模式运行时,EXE 先解压到临时目录,sys._MEIPASS 指向该目录;源码运行时则回退到脚本所在目录。

4.3 常见报错排查

现象 原因 解决
打包成功但运行时闪退 依赖 stdin/stdout 却被加 -w 去掉 -w;先本地 python 脚本.py 验证
No module named 'xxx' 动态 import,分析器漏掉 --hidden-import xxx
运行时找不到数据文件 未用 _MEIPASS 解析路径 用上面的 resource_path()
EXE 体积过大 打入了无关依赖 --exclude-module 排除,或改用 -D 模式
杀毒软件误报 PyInstaller 产物特征 代码签名或加白名单(无法根治)

4.4 其他要点

  • -F-D 互斥,只需指定一个
  • -w-c 互斥,只需指定一个
  • 图标必须是有效 .ico 文件,不能直接把 .png 改后缀
  • 打包产物是给目标电脑用的,不要求目标电脑安装 Python
  • 重复打包时加 --noconfirm --clean 可避免残留缓存导致异常
  • 完整参数以官方文档为准:https://pyinstaller.org/en/stable/usage.html

五、速查表

# CLI 程序(最简)
pyinstaller -F 程序.py

# GUI 程序
pyinstaller -F -w 程序.py

# GUI + 图标 + 资源
pyinstaller -F -w -i 图标.ico --add-data "config.json;." 程序.py

# 完整参数
pyinstaller -F -w -i 图标.ico \
    --add-data "config.json;." \
    --distpath dist --specpath spec --workpath build \
    --noconfirm --clean 程序.py