简介:PyInstaller 3.5 版本完整源码压缩包,面向需要将 Python 程序打包成独立可执行文件的开发者,解决目标机器缺少 Python 运行环境时程序难以分发和快速部署的常见难题,适用场景涵盖 Windows、Linux、macOS 等系统下的项目交付、工具发布与离线安装。压缩包总计 1307 个文件,包含大量 Python 脚本、文本文档、C 语言头文件与实现文件,同时配有配置文件、图标素材和构建脚本等辅助内容,整体大小约 3.93MB,体积不大但结构清晰,覆盖打包器的主体逻辑与多平台适配实现。目前已有 2229 人学习下载。借助这些源码与脚本,读者可以自行完成 PyInstaller 的安装或二次构建,深入理解依赖收集、启动引导、资源封装等关键机制,还可以通过规格文件、路径配置和清单文件学习 Python 打包的整体流程,为排查打包异常、定制个性化可执行程序提供直接参考。 这段时间在折腾旧项目,手头正好有一份pyinstaller-pyinstaller-v3.5.zip,顺手把打包 Python 脚本成 exe 的完整流程重跑了一遍。网上聊 PyInstaller 的文章不少,但要么直接讲最新版,要么只给个命令就完事,很少有把“拿到 zip 怎么装”、“怎么打包”、“装完跑不起来怎么办”串起来讲的。这篇就基于我这次实操,把从解压安装到踩坑排错的过程完整记录下来,也给还在用旧版本或者从离线渠道拿到源码包的朋友一个参考。
PyInstaller 是干嘛的,一句话说就是:把 Python 脚本打包成独立可执行程序,让没有装 Python 环境的电脑也能直接运行你的程序。它支持 Windows、Linux、macOS 三大平台,但最常见的需求就是把.py文件打包成 Windows 下的.exe。这篇文章适合这些读者:刚入门 Python、想把小工具发给同事用的人;在公司内网没法直接pip install、只能靠离线包安装的人;以及遇到“PyInstaller 装完却跑不起来”这类问题,想一次性搞清楚原因的人。
1. 为什么我用的是 3.5 这个老版本
1.1 版本背后的兼容性逻辑
你拿到的文件名是pyinstaller-pyinstaller-v3.5.zip,这其实是 PyInstaller 官方在 GitHub Releases 里发布的源码压缩包,命名规则是“仓库名-分支名-版本号”。3.5 是 2017 年左右发布的版本,当时支持的 Python 版本是 2.7 和 3.3 到 3.6。放到现在看,它属于一个“老古董”了,但依然有相当一批人不得不用它——老项目锁定版本、内网环境无法更新、某些第三方库只兼容旧版 Python,这些场景我都遇到过。
如果是在 2024 年之后的新环境里从头安装,我肯定优先建议你用最新版,命令就一行:pip install pyinstaller。但如果你拿到的就是这个 3.5 的 zip,或者你的 Python 版本是 3.6 及以下,那跟着这篇文章走完全没问题。理解了这一点,后面遇到“版本不兼容”的报错时,你就知道根源在哪里了。
1.2 PyInstaller 的核心打包原理
在动手之前,有必要花一分钟理解 PyInstaller 的打包原理,否则后面遇到问题会一头雾水。PyInstaller 做的事情本质上是“捆绑”:它把你的 Python 脚本、脚本里import的所有模块、Python 解释器本身,以及程序运行所需的动态链接库(比如.dll文件),全部拷贝到一个目录或者一个 exe 文件里。
这个原理决定了两个重要结论:第一,打包出来的 exe 体积通常很大,一个最简单的print("hello")打包出来也有 5MB 以上,因为里面塞了一个完整的 Python 解释器;第二,打包过程中如果遇到了它“看不见”的模块,比如通过字符串形式动态导入的库,就会出现运行时报错“ModuleNotFoundError”。理解这两点,后面排错就有方向了。
2. 从 zip 压缩包到命令行可用:完整安装步骤
2.1 安装前的环境检查
不管你是从官网下载的 zip,还是同事内网传给你的,安装前都要先确认 Python 环境。打开命令行,输入:
python --version如果输出的是Python 3.6.x或更低版本,那这个 3.5 的 PyInstaller 可以直接用。如果输出的是Python 3.7及以上,那老老实实去用新版吧,3.5 装上去大概率会报不支持。这里也顺便解释一下为什么:PyInstaller 的打包过程需要解析 Python 的字节码和内部数据结构,Python 每个版本的小版本升级都可能改变这些结构,所以 PyInstaller 对新版 Python 的支持需要专门适配。
还有一个环境细节容易被忽略:PyInstaller 在 Windows 上打包时,需要读取 PE 文件的导入表信息,所以它依赖一个叫pefile的第三方库。如果是通过 pip 在线安装,这些依赖会自动装好;但如果你是完全离线的环境,还需要单独准备pefile、altgraph等依赖包。
2.2 解压安装的两种方式
拿到pyinstaller-pyinstaller-v3.5.zip后,安装方式有两种,我建议优先用第一种。
第一种,直接用 pip 安装本地压缩包,这是最省事的方式:
pip install pyinstaller-pyinstaller-v3.5.zippip 会自动识别压缩包里的setup.py,完成构建和安装,并且自动处理依赖(前提是能访问 PyPI,或者本地已经备好了依赖包)。
第二种,手动解压后运行 setup.py:
# 解压 unzip pyinstaller-pyinstaller-v3.5.zip # 进入目录(注意实际解压出来的文件夹名可能略有不同) cd pyinstaller-pyinstaller-3.5 # 安装 python setup.py install这种方式本质上和第一种没区别,只是把“解压”这个动作拆开做了。手动解压的好处是你可以在安装前看看源码结构,坏处是如果依赖缺失,你得到的是裸的报错信息,需要手动去补装依赖。
2.3 验证安装是否成功
安装完成后,验证一下是否装好:
pyinstaller --version如果输出版本号,说明安装成功。但实际工作中,这一步经常出问题,最常见的就是“pyinstaller 不是内部或外部命令”。原因是 pip 安装的可执行文件位于 Python 安装目录下的Scripts子目录,而这个目录没有被加入系统的 PATH 环境变量。解决办法有两个:要么把C:\Users\你的用户名\AppData\Local\Programs\Python\Python36\Scripts添加到系统环境变量,要么绕开命令,使用模块方式调用:
python -m PyInstaller --version我自己更习惯用python -m PyInstaller这种方式,因为它不依赖 PATH 配置,环境变了也不影响。后面的打包命令也都基于这种方式。
3. 打包 exe:从零到一的完整实操
3.1 写一个测试脚本
安装验证通过后,先拿一个简单的脚本练手。我建了一个hello.py,内容就是一个带输入输出的小程序:
print("你好,我是打包测试程序") input("按回车键退出...")这里故意加了一个input(),作用是在双击 exe 运行时让窗口停下来等待输入,方便我们确认程序确实跑起来了。如果你不加,程序执行完会瞬间闪退,你根本看不清结果。
3.2 常用打包参数逐个拆解
PyInstaller 打包命令的基本格式是:
python -m PyInstaller [参数] 你的脚本.py第一次打包的人,只要记住下面这几个参数就够用了:
| 参数 | 作用 | 使用场景 |
|---|---|---|
-F/--onefile | 打包成单个 exe 文件 | 想发给别人一个文件,最常用 |
-D/--onedir | 打包成文件夹(默认模式) | 追求启动速度、方便调试 |
-w/--windowed | 运行时不显示控制台窗口 | GUI 程序必加 |
-i/--icon | 指定 exe 图标 | 美化程序图标 |
--name | 指定生成的 exe 名称 | 自定义程序名 |
--hidden-import | 手动指定隐藏导入的模块 | 动态导入的库打包时用 |
--add-data | 添加额外数据文件 | 配置文件、图片、音频等 |
这里我特别说明一下-F和-D的选择。-F打包出的单文件看似方便,但每次启动,PyInstaller 都要把这里面的解释器和依赖库解压到系统临时目录才能运行,所以启动速度明显偏慢,有些杀毒软件还会额外扫描这个解压过程。-D模式生成的是一个大文件夹,里面有 exe 和一些动态库文件,启动速度快,但分发时得把整个文件夹压缩发过去。如果是给同事用一个工具类软件,我建议-F单文件,省得对方搞不清文件夹里哪些文件必须保留。
3.3 一次完整的打包过程演示
我用带图形界面的方式来演示,因为-w参数是 GUI 程序打包的标配。新建app.py:
import tkinter as tk root = tk.Tk() root.title("PyInstaller 打包测试") label = tk.Label(root, text="打包成功!") label.pack(padx=20, pady=20) root.mainloop()然后执行:
python -m PyInstaller -F -w --name 测试程序 app.py命令执行过程中,PyInstaller 会先分析导入依赖,再生成一个.spec配置文件,接着执行构建流程。这几步如果你是在终端里看到的,最后出现completed successfully,就说明打包成功了。去dist目录下就能看到生成的 exe 文件。
还有一个实战小技巧:打包完成后,PyInstaller 会在当前目录生成三个东西——build目录(构建过程产生的临时文件)、dist目录(最终产物)、和.spec文件(配置文件)。发布时只需要dist里的内容,build目录可以随时删除,下次打包会自动重建。.spec文件建议保留,因为如果你后续要调整打包参数(比如更换图标),直接改.spec文件再执行python -m PyInstaller 测试程序.spec比重新敲一长串命令更方便。
4. 安装完运行不了?这些坑我全踩过
4.1 pyinstaller 命令本身跑不起来
这个问题分两种情况,一种是安装阶段就出错,另一种是打包出来的 exe 运行阶段出错,很多人会把两者混为一谈。先看安装阶段的。
情况一:“pyinstaller 不是内部或外部命令”。这就是前面提到的 PATH 环境变量问题。验证方法是执行python -m PyInstaller --version,如果这条能正常输出版本号,那就确认是可执行文件路径没被系统找到。解决:把 Python 的Scripts目录加进 PATH,或者干脆以后都用python -m PyInstaller这种模块调用方式。
情况二:安装过程中报错,提示 Python 版本不受支持。例如Unsupported Python version。这说明你的 Python 版本和 PyInstaller 3.5 不匹配。我前面已经反复强调过,3.5 只支持 Python 3.6 及以下。这时候要么换 Python 版本,要么换 PyInstaller 版本,没有第三条路。如果你被 Python 版本锁死了,还有一个思路是使用pyenv这样的版本管理工具,在同一台电脑上同时安装多个 Python 版本,按项目切换。
4.2 打包出的 exe 双击后闪退
这是占比最高的运行时报错场景,发生概率远超你的想象。闪退的根本原因是:程序运行过程中抛出了未捕获的异常,但因为没有控制台窗口,错误信息一闪而过,你根本来不及看。排查方法很简单:先用控制台模式跑一遍。
回到刚才的流程,把-w参数去掉,重新打包:
python -m PyInstaller -F app.py然后双击或在命令行里运行生成的 exe。这次因为保留了控制台窗口,程序在任何一行代码报错时,窗口会停下来显示完整的报错堆栈,包括是哪一行代码、缺少哪个模块。我看到过最多的报错就是ModuleNotFoundError: No module named 'xxx',原因就是我开头讲的动态导入问题。
解决办法是找到报错的模块名,用--hidden-import参数强制打包:
python -m PyInstaller -F --hidden-import xxx app.py还有一种情况比较隐蔽:程序里用了文件路径,比如读取config.ini。你打包成单文件模式后,win 路径跟开发时跑代码路径根本就不是一回事。开发时当前工作目录是脚本所在目录,打包后的 exe 运行时,当前工作目录可能是C:\Windows\System32,或者被解压到了系统的临时目录。想稳定获取资源文件路径,要这样写:
import sys import os # 判断是打包环境还是开发环境 if hasattr(sys, '_MEIPASS'): # 打包后临时解压目录 base_dir = sys._MEIPASS else: base_dir = os.path.dirname(os.path.abspath(__file__)) config_path = os.path.join(base_dir, 'config.ini')这段代码是每个用 PyInstaller 打包的程序都应该掌握的基础写法,很多新人栽跟头就是栽在这里。
4.3 exe 被杀毒软件拦截或误报
打包后的 exe 一放到别人电脑上,就被 360 或 Windows Defender 干掉,这也是高频问题。原因很简单:Python 程序的执行特征(从临时目录释放文件、写入注册表等等)与某些恶意软件行为相似。PyInstaller 打包的单文件 exe 尤其容易被误报,因为它启动时要解压大量文件到临时目录然后执行。
这个问题没有 100% 根治的办法,但有几个缓解策略:
- 换用
-D目录模式而非-F单文件模式,减少解压动作,误报率会降低不少。 - 对 exe 进行代码签名,签名后的程序可以显著降低杀毒软件的误报率。个人开发者可以用开源免费的签名工具,或者申请各大云厂商的代码签名证书。
- 在项目里写清楚程序来源,外发时附上源码或说明文档,减少被同事或客户误删的概率。
4.4 打包后的 exe 在别的电脑上提示缺少 DLL
这种情况主要发生在目标电脑缺少 VC++ 运行库时,比如VCRUNTIME140.dll找不到。PyInstaller 打包的默认目标是“当前这台机器能跑”,而不是“所有 Windows 机器都能跑”。如果你的开发环境里装了 Visual Studio 的运行时库,而目标机器是精简版的 Windows,就可能缺依赖。缓解办法有两个:一是在目标机器上安装 VC++ 可再发行组件包;二是让开发环境尽量“干净”,不要在系统 Python 环境里乱装各种包,用干净的虚拟环境来打包,这样打包出来的产物会更接近最小依赖。
5. 关于 3.5 版本与打包心得
最后再聊点操作之外的体会。3.5 这个版本在今天看来确实老了,缺少新版的一些优化,比如对 Python 3.7+ 的支持、更快的构建速度、更好的资源文件处理。但它也足够稳定,我在多个老项目里用了很久,没出过什么幺蛾子。如果你是被迫用这个版本,牢记两点:第一,确保 Python 版本在 3.6 及以下;第二,打包前用干净的虚拟环境,避免把无关的包带进产物里。
如果你可以自由选择版本,我的建议是直接用最新版。新版本在兼容性和性能上的改进非常明显,安装只需要一行pip install pyinstaller,文档也更完善。但无论是哪个版本,排错思路是完全一致的:先用控制台模式看清楚报错,再针对性地处理依赖、路径、权限这三类最常见的问题。
打包这件事,本质上就是“把调试期间的经验,复制给别人也能用”的过程。你踩过的每一个坑,都会变成下一轮更顺手的打包流程。希望这篇实操笔记帮你在 PyInstaller 上少走点弯路。
本文还有配套的精品资源,点击获取