定义
PyInstaller是一个把Python应用程序及其全部依赖项汇集到一个包中的工具,打包后的程序无需在目标机器上安装Python解释器或任何模块即可运行。按照项目手册的说明,它支持Python 3.8及更新版本,并针对Windows、macOS和Linux进行测试[1]。
与编译器不同,PyInstaller并不把Python源码翻译成机器码。它读取用户提供的脚本,分析代码以发现运行所需的每一个模块和库,然后把包括当前Python解释器在内的这些文件复制到一起,放进一个文件夹或单个可执行文件[3]。因此它更接近一种静态链接器,把解释器、程序、库和数据文件聚合为可分发的整体[4]。
该工具最初由Gordon McMillan在McMillan Enterprises公司开发,早期的名称源自「McMillan Enterprises Installer」[5]。2005年起项目由Giovanni Bajo等人接手,2010年以后由PyInstaller Development Team继续维护[2]。
原理
打包过程的核心是分析阶段。PyInstaller遍历脚本的字节码,找出其中的import语句,再对被导入的模块递归查找,直到得到一份完整的依赖清单[3]。对于egg格式的分发包以及Qt、wxPython、TkInter、Django等重要第三方包,工具内置了识别逻辑[3]。
收集到的Python模块被压缩进一种名为ZlibArchive的归档文件,其目录是一张以import名称为键、以偏移量和长度为值的字典;运行时的导入不再搜索sys.path,而是直接查表、读取并解压,即使采用最大压缩也比常规导入更快。二进制库和任意数据文件则装入CArchive,它类似zip文件,目录表放在末尾并附有指向表头的cookie,因此可以附加在ELF或COFF可执行文件之后,由程序自身打开并定位。
每个打包后的应用都嵌入一份引导程序(bootloader),负责设置运行环境并启动应用[6]。在单文件模式下,引导程序启动时会先在系统临时目录中建立一个名为_MEIxxxxxx的文件夹(xxxxxx为随机数),把内嵌归档中的支持文件解压进去,然后在该目录中按单目录模式的方式运行;程序正常结束时,引导程序会删除这个临时文件夹[7]。
打包的构建规则写在规格文件中,它是一个真正的Python源码文件,由Analysis、PYZ、EXE、COLLECT等类调用组成。Analysis对象扫描源码并列出所需的纯Python模块、二进制模块和数据文件,PYZ创建归档,EXE生成可执行文件,COLLECT负责输出目录[8]。
发展历程
项目的前身是2002年McMillan Enterprises公司的McMillan Enterprises Installer,相关版权一直沿用至今[2]。2011年5月发布的1.5版本增加了对Windows 64位的支持,并为Linux 32位与64位、Darwin 32位提供了预编译引导程序,用户不再需要自行编译[9]。同期项目开始使用waf重写引导程序的构建系统[9]。
2015年前后,源码托管迁移至GitHub,核心维护团队包括Hartmut Goebel、Martin Zibricky、David Vierra和David Cortesi等[10]。3.0版本是一次较大规模的重写,加入了对Python 3的支持,并通过自动化测试改善代码质量[3]。
6.6版本为Analysis对象和命令行接口引入了显式的字节码优化设置,即--optimize选项[11]。在6.22.1版本中,引导程序增加了对运行时环境的额外校验,用于防止伪造内部环境变量诱使可执行文件使用任意应用目录。
应用
PyInstaller的主要用途是把Python程序分发给没有Python环境的用户。使用者只需运行一条命令并指定主脚本,生成的打包结果会出现在dist目录中,可以直接交给他人执行[1]。打包既可选择生成包含全部文件的单个可执行文件,也可选择生成一个包含可执行文件与依赖文件的目录[12]。
在输出形式上,单文件模式便于分发,但启动时要先解压到临时目录,因此比单目录模式慢;单目录模式的文件结构清晰,适合以框架形式组织代码,便于维护[13]。图形界面程序可以隐藏控制台窗口,也可以设置自定义图标,或借助UPX压缩以减小体积[12]。
对于由多个应用组成、共享第三方库的产品,规格文件中的MERGE函数可以找出各应用的公共依赖并加以合并,使每个依赖只保存一份,代价是部分应用的启动时间略有增加[8]。
局限
PyInstaller不是交叉编译器。要生成Windows程序必须在Windows上运行它,要生成Linux程序必须在Linux上运行,输出结果与当前操作系统、Python版本以及32位或64位字长绑定。
并非所有依赖都能被自动识别。使用__import__()配合变量、在运行时修改sys.path等写法,分析阶段无法察觉,需要用户通过命令行参数、规格文件或钩子文件补充隐藏导入[3]。ctypes的检测只覆盖以裸文件名和字面字符串形式引用共享库的用法,使用绝对路径或变量传递库路径时无法被识别[11]。
打包后的程序体积通常明显增大,因为解释器与全部依赖被一并放入,UPX压缩或排除无用模块只能部分缓解[4]。单文件程序还需要在支持符号链接的文件系统上解压;若程序崩溃或被强制结束,_MEIxxxxxx临时目录不会被清理,多次崩溃会持续占用磁盘空间[14]。
在Windows上使用--noconsole构建的窗口程序没有控制台,标准输入输出不直接可用[14]。多进程方面,目前仅支持标准库的multiprocessing模块,并且必须在调用任何多进程功能之前执行freeze_support(),否则可能出现进程反复自我启动的循环[14]。
参见
参考资料
- PyInstaller Manual [引用日期2026-10-14]
- License [引用日期2026-10-14]
- PyInstaller Manual [引用日期2026-10-14]
- 如何将python代码打包成exe文件---PyInstaller打包之神 [引用日期2026-10-14]
- Revision 046967bd-7a00-4165-8b88-fba906caf029 [引用日期2026-10-14]
- Requirements [引用日期2026-10-14]
- stackoverflow.com 上的网页 [引用日期2026-10-14]
- Using Spec Files [引用日期2026-10-14]
- pyinstaller - PyInstaller Overview [引用日期2026-10-14]
- /bootloader/ /PyInstaller/loader [引用日期2026-10-14]
- readthedocs.org 上的文件 [引用日期2026-10-14]
- Python实用记录(十三):python脚本打包exe文件并运行 [引用日期2026-10-14]
- 仅限pyInstaller生成可执行文件 [引用日期2026-10-14]
- Common Issues and Pitfalls [引用日期2026-10-14]