本文总结如何将 python
文件打包成可执行文件 .exe
。
Updated: 2022 / 10 / 7
py
文件打包成 exe
文件的方式一共有三种:
py2exe
PyInstaller
cx_Freeze
python
作为一门解释型脚本语言,它有三种发布方式 1:
py
文件Python
环境并且安装依赖的各种库;pyc
文件pyc
文件是 Python
解释器可以识别的二进制码,可跨平台的,需要使用者安装相应版本的Python
和依赖库。python
环境和依赖库,可针对不同平台需要打包不同的可执行文件( Windows
, Linux
, Mac
, …)PyInstaller freezes (packages) Python applications into stand-alone executables, under Windows, GNU/Linux, Mac OS X, FreeBSD, Solaris and AIX.
当通过 Python
开发的程序应用需要在其他设备上运行时,需要安装 Python
环境及相应的第三方库,但对方是非技术人员或在离线环境下时,搭建环境比较麻烦,此时可考虑使用 PyInstaller
工具将 python
解析器和脚本打包成一个可执行的文件。
无论是生成的文件夹里的可执行文件或者只打包成一个可执行文件都可以直接运行,前者需要把整个文件夹都给别人。可能运行效率可能会降低,好处就是在使用者的机器上可以不用安装 python
和脚本所依赖的库。
- 打包成一个文件夹 2
传输方便(压缩,解压到另外一个电脑,再双击 exe 文件就可以运行),而且debug方便。使用这一方式时,很容易调试在打包
exe
时出现问题。可以准确地看到pyinstaller
收集了哪些文件到该文件夹。
如果代码发生改变(不涉及依赖包的改变的话),只需要发给别人更新过的.exe
文件即可。这比更新整个文件夹要方便地多。但是,如果脚本引入了新的依赖包或更改了依赖包,则需要重新分发这一整个文件夹。
- 打包成一个单独的文件 2
pyinstaller
可以把所有的脚本及其依赖包都打包到一个.exe
文件中,优点是看不懂文件夹中其他内容的用户可以只得到一个是做什么的.exe
文件。但是每次更新都要重新发布全部内容(只有1个
.exe
但是体积会大一些),同时,单个文件比单个文件夹启动要慢。
利用 PyInstaller
对指定的的脚本打包时,会先分析脚本所依赖的其他脚本,然后根据导包路径去查找,把所有相关的脚本收集起来,包括 Python
解析器,然后根据你的命令参数可分别生成文件夹,或者打包成一个可执行文件。
注意
PyInstaller
本身可跨平台使用,但通过 PyInstaller
打包出来的文件是无法跨平台的,比如在 Linux
下使用 PyInstaller
打包 Python
程序得到的文件只可在 Linux
下运行;在 Windows
下打包的只可在 Windows
下运行。使用 Pyinstaller
打包得到的 .exe
文件是特定于具体的操作系统和特定的 python
版本的。
也就是说,不具备可移植性。
若要为以下的环境准备发布版本:
应该针对该平台进行打包,即可以在那个 python
版本,那个操作系统下运行 Pyinstaller
。然后执行 Pyinstaller
的 Python
编译器是 bundle
(包)的一部分,它会特定于具体的操作系统和特定的字长。
参考这里 3
马克
PyInstaller analyzes yourprogram.py and:
Writes yourprogram.spec in the same folder as the script
Creates a folder build in the same folder as the script if it does not exist
Writes some log files and working files in the build folder
Creates a folder dist in the same folder as the script if it does not exist
Writes the yourprogram executable folder in the dist folder
In the dist folder you find the bundled app you distribute to your users
联网:
[x] 安装
pip install pyinstaller
,或者,
python -m pip install pyinstaller -i http://mirrors.aliyun.com/pypi/simple/
,使用 -i
指定镜像即可
[x] 更新
pip install --upgrade pyinstaller
离线:
先去官网下载离线安装源 (https://pypi.org/project/PyInstaller/#files
),再进行安装。
注意 4
win
安装 PyInstaller
时需要额外安装另外两个模块,pywin32
或 pypiwin32
,以及 pefile
。
如果使用 pip
进行安装,但是还没有安装 pywin32
时,会自动安装 pypiwin32
,pefile
没有时也会自动安装。
基本的命令为 pyinstaller -option xxx.py
。
其中 xxx.py
就是需要打包的 python
脚本,option
为 pyinstaller
中的参数选项,其中 option
默认为 -D
。
打包完成后主要生成两个文件夹和一个 spec
文件:
dist
文件夹,运行 pyinstaller
命令后会在相同路径下生成,该文件夹下应该会有一个跟程序同名的文件夹(除非使用 pyinstaller -F
命令打包),打包好的 exe
就在该文件夹下。如果在命令行中或者
.spec
文件中指定的.py
文件不止一个,比如pyinstaller xxx1.py xxx2.py
,pyinstaller
会依次分析并执行,并把第一个py
名称作为.spec
和dist
文件下的文件夹和程序的名称。
build
文件夹,运行 pyinstaller
命令后会在相同路径下生成,相当于 Pyinstaller
的工作空间,Pyinstaller
运行相关的文件和日志都在这个文件夹中,打包完成后可以直接删除;.spec
文件,即配置文件,用于打包复杂的 python
项目。options
参数说明参数名 | 描述 | 说明 |
---|---|---|
-h / --help |
显示帮助信息 | 无 |
-v / --version |
显示版本号 | 无 |
--distpath |
生成文件放在哪里 | 默认:当前目录的 dist 文件夹内 |
参数名 | 描述 | 说明 |
---|---|---|
-D |
生成 one-folder 的程序(默认),比如 pyinstaller -D demo.py |
生成结果是一个目录,各种第三方依赖文件和 DLL 文件等和 demo.exe 同时存储在该目录下。打包的文件始终在 Pyinstaller 的bootloader (根引导)中开始执行,这是打包的文件夹中可执行文件的核心。 Pyinstaller bootloader 是活动平台(windows GNU / linux / Mac OS 等)上的一个二进制可执行程序,当用户启动程序时,其实是 bootloader 在运行。bootloader 创建了一个临时的 Python 虚拟环境,这样 Python 编译器 (interpreter ) 就可以在这个脚本文件夹中找到所有引入的模块 / 库。bootloader 启动了一个 Python 编译器的副本来执行脚本,后续的执行正常都是从这里开始的,提供被包括在脚本文件夹中所有支持的文件 2。 |
-F |
生成 one-file 的程序,比如 pyinstaller -F demo.py |
只在 dist 文件夹中生成一个结果是 demo.exe 文件,不生成其他 dll 文件,适用于没有多依赖 .py 文件的单个文件。可以覆盖打包,无论打包多少次都将是最新的。与 -D 模式生成的 exe 程序相比,在启动速度上会慢一些,因为它需要先解压 exe 文件并生成一个唯一的临时环境来运行程序,关闭环境时也会自动删除这个临时环境。而 -D 模式的程序本身就是解压好的,运行完也不需要执行删除操作。这一点,在程序的大小比较大时,这个差别就很明显了 2。 运行程序的时候,也会有一个 BootLoader ,但是会根据操作系统创建一个名为 _MElxxxxxx 的文件夹,用作这个程序的临时运行环境(不只是 python 环境),这个 xxxxxx 是一个随机的数字。-F 模式程序启动时因为需要解压并拷贝依赖和资源文件到临时运行环境 _MExxxxxx ,所以启动速度比 -D 模式慢,运行结束后会删除临时运行环境的文件夹。在 Linux 和相关系统中,可能有 no-execution 选项,但是对于 -F 模式程序是不兼容的。由于 _MElxxxxxx 是唯一的,所以可以同时运行多个程序,多个程序互不干涉。如果程序崩溃了,或者强行结束(在 win 的任务管理器中杀死了进程),_MElxxxxxx 文件夹是不会被删除的,所以频繁崩溃或结束进程会导致有多个 _MElxxxxxx 文件夹,会非常占磁盘空间,可以使用 --runtime-temdir 指定 _MElxxxxxx 的存放位置。-F 模式程序如果在运行时遇到了权限问题,可以使用 -D 模式程序替代。 |
-K |
-tk ,在部署时包含 TCL / TK 。 |
|
-n NAME |
--name NAME ,生成 .exe 文件和 .spec 的文件名 |
默认为传入的 .py 脚本或者 .spec 文件的名称。 |
--specpath DIR |
指定生成 spec 文件的路径,默认为当前路径。 |
比如,pyinstaller --specpath ./SPEC demo1.py demo2.py |
--distpath DIR |
指定生成 dist 的目录,默认为 ./dist |
|
--workpath WORKPATH |
指定 pyinstaller 的工作目录,即 build 文件夹,默认为 ./build 。 |
|
-y / --noconfirm |
替换输出目录时不询问,默认输出目录是 SPECPATH / dist / SPECNAME |
|
--upx-dir UPX_DIR |
指定 UPX 程序的路径,默认为 程序执行路径 , 即双击某个文件时,系统自动查找对应程序的路径。UPX 为一个压缩程序,需要自行下载,可以将 exe 压缩为 zip 格式的文件,并且压缩效率非常高。如果打包后的 exe 程序非常大的话,为了避免客户下载时文件太大的问题,可以使用 UPX 工具。 |
|
-d |
-debug ,产生 debug 版本的可执行文件。比如 pyinstaller demo.py -d |
|
--noupx |
不需要 UPX (即便可用) |
|
-a / --ascii |
不包含编码。在支持 Unicode 的 python 版本上默认包含所有的编码。 |
|
--clean |
在 pyinstaller 开始执行前清楚缓存并删除临时文件(一般存储在 C:\Users\Administrator\AppData\Roaming\pyinstaller )。 |
|
--log-level LEVEL |
指定打印的日志等级,默认为 INFO 。日志等级有 TRACE , DEBUG , INFO , WARN , ERROR , CRITICAL 。如果在打包时遇到了问题,为了方便定位问题,可以使用这个参数来查看特定级别的日志信息。 |
参数名 | 描述 | 说明 |
---|---|---|
--add-data SRC;DEST |
指定需要添加非二进制文件路径或者文件夹路径,比如图片和 pdf 文件等,这个选项可以使用多次。这个命令其实就是将需要的文件或者文件夹拷贝到指定的路径下,在 -D 模式下,可以看情况在程序打包完成后自己手动拷贝过去。 |
|
--add-binary SRC;DEST |
指定需要添加的二进制文件路径,比如 DLL 文件、动态链接库或者共享文件对象等,这个选项可以使用多次。同 -add-data 命令一样,是一个拷贝数据的功能。 |
|
-o DIR |
--out=DIR ,指定 spec 文件的生成目录。如果没有制定,则默认使用当前的目录以生成 spec 文件。 |
|
-p DIR |
--paths DIR ,设置导入路径 (和使用 PYTHONPATH 效果相似).可以用路径分割符 (Windows 使用分号, Linux 使用冒号)分割。指定多个目录,也可以使用多个 -p 参数来设置多个导入路径,让 pyinstaller 自己去找程序需要的资源 5。 |
|
--hidden-import MODULENAME/--hiddenimport MODULENAME |
指定脚本中需要隐式导入的模块,比如在 __import__ 、imp.find_module() 、exec 、eval 等语句中导入的模块,这些模块 PyInstaller 是找不到的,需要手动指定导入,这个选项可以使用多次。 |
|
--additional-hooks-dir HOOKSPATH |
指定额外 hook 文件(可以是 py 文件)的查找路径,这些文件的作用是在 PyInstaller 运行时改变一些 Python 或者其他库原有的函数或者变量的执行逻辑(并不会改变这些库本身的代码),以便能顺利的打包完成,这个选项可以使用多次。 |
|
--runtime-hook RUNTIME_HOOKS |
指定自定义的运行时 hook 文件路径(可以是 py 文件),在打好包的 exe 程序中,在运行这个exe 程序时,指定的 hook 文件会在所有代码和模块之前运行,包括 main 文件,以满足一些运行环境的特殊要求,这个选项可以使用多次。 |
|
--exclude-module EXCLUDES |
指定可以被忽略的可选的模块或包,因为某些模块只是 PyInstaller 根据自身的逻辑去查找的,这些模块对于 exe 程序本身并没有用到,但是在日志中还是会提示 module not found ,这种日志可以不用管,或者使用这个参数选项来指定不用导入,这个选项可以使用多次。 |
|
--key KEY |
指定用于 Python 字节码加密的 key ,key 是一个16个字符的字符串。 |
Windows
和 Mac
特有的参数参数名 | 描述 | 说明 |
---|---|---|
-c |
提供一个命令行窗口进行 I/O ,比如 pyinstaller -c demo.py |
与 -w 相反,默认含有此参数 |
-w |
- ,程序运行后隐藏命令行窗口,比如 pyinstaller -w demo.py |
编写 GUI 程序时使用此参数有用,比如当你不需要使用命令行窗口作为程序的 I/O 时;如果想程序运行的时候与程序进行交互,则不加该参数。 |
-i |
--icon ,为 main.exe 指定图标,比如 pyinstaller -i D:\icons\demo.ico demo.py 。 |
给生成的 demo.exe 文件设置一个自定义的图标 D:\icons\demo.ico 。 |
当执行打包命令时,PyInstaller
首先建一个 sepc
(specification
) 文件 script.spec
,默认放在当前文件夹下,默认名为 xxx.spec
配置文件。
spec
文件的作用是什么呢?生成 spec
文件时可以什么都不指定,它会告诉 PyInstaller
如何处理你的 py
文件,它会将你的 py
文件名字和输入的大部分参数进行编码。PyInstaller
通过执行 spec
文件中的内容来生成 exe
,有点像 makefile
。
spec
文件其实就是一个 py
文件,在编辑时可以直接将它当作一个 py
文件来使用。
正常使用中我们是不需要管 spec
文件的,但是下面几种情况需要修改 spec
文件:
spec
文件中单独用一个列表变量来制定,可读性和可维护性会高很多。include
一些 PyInstaller
不知道的库;.dll
或者 .so
文件,同样可以在 spec
文件中单独用一个列表变量来制定。run-time
选项和hook
文件;若我们所需的场景符合上面所描述的任意一个,则需要在打包前生成 spec
文件并修改。生成一个纯粹的 spec
文件的命令如下:
pyi-makespec -options xxx.py [other scripts]
出现图片上的提示,即为生成 spec
文件成功。
生成并修改 spec
文件后,可以根据 spec
文件进行打包,具体命令如下:
pyinstaller xxx.spec
spec
文件默认的结示例如下:
block_cipher = None
a = Analysis(
['script.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='script',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='script',
)
spec
文件是一个 python
脚本,文件中主要包含4个 class
: Analysis
, PYZ
, EXE
和COLLECT
4’ 6。
变量 | 含义 |
---|---|
a |
Analysis 的实例,要求传入各种脚本用于分析程序的导入和依赖。 |
scripts ,它是一个脚本列表,可以传入多个 py 脚本,效果与命令行中指定多 py 文件相同,即 py 文件不止一个时,比如 pyinstaller xxx1.py xxx2.py ,pyinstaller 会依次分析并执行,并把第一个 py 名称作为 spec 和 dist 文件下的文件夹和程序的名称; |
|
pathex ,同命令 -p DIR / --paths DIR ,其实默认就有一个 spec 的目录,如果使用命令添加的话,会首先添加命令中指定的目录,再添加默认的路径。它定义了打包的主目录(生成 spec 文件的时候会自动填充好主目录路径),对于在此目录下的 py 文件可以只写文件名不写路径。 |
|
datas ,添加数据文件,命令是 --add-data ,spec 。文件中是 Analysis 的 datas = [] 参数,datas 是一个元素为元祖的列表,每个元祖都有两个元素,元祖的基本格式为(”原项目中资源文件路径” , ”打包后的文件路径”) ,都必须是字符串类型,元祖的第一个元素为数据文件或文件夹,元祖的第二个元素为运行时这些文件或文件夹的位置。例如, datas = [("src/README.txt", "."), ] ,也可以在命令中中这样写 pyinstaller --add-data "src/README.txt; ." myscript.py ,表示打包时将文件 src/README.txt 添加到相对于 spec 文件的根目录下,指定文件时是相对于 spec 来进行寻找的,而不是要打包的 exe 程序路径。可以使用通配符 datas = [("/mygame/sfx/*.mp3", "sfx")] ,表示将 /mygame/sfx/ 目录下的 .mp3 文件都拷贝到 sfx 文件夹中。也可以添加整个文件夹 datas=[("/mygame/data", "data")] ,表示将 /mygame/data 文件夹下所有的文件都拷贝到 data 文件夹下。 |
|
binaries ,添加二进制为摁键,效果同命令 --add-binary ,也是一个列表,定义方式与 datas 参数一样。 |
|
hiddenimports ,同命令 --hidden-import MODULENAME/--hiddenimport MODULENAME 。一般而言都是在生成可执行程序 exe 的过程中抛出 No Module named xxx 错误才会发现这些遗漏的模块,碰到这些异常,只需在 spec 文件中添加对应的遗漏模块即可。 |
|
hookspath ,同命令 --additional-hooks-dir HOOKSPATH |
|
runtime_hooks ,同命令 --runtime-hook RUNTIME_HOOKS |
|
exclude ,同命令 --exclude-module EXCLUDES ,以排除某些用不到的模块 5。 |
|
PYZ |
PYZ 的实例,是一个 .pyz 文件,包含程序运行需要的所有依赖; |
EXE |
EXE 的实例,这个类用来处理 Analysis 和 PYZ 的结果的,也是用来生成最后的 exe 可执行程序; |
console , 设置是否显示命令行窗口,和命令 -w / -c 作用一样。 |
|
icon ,设置程序图标,和命令 -i / --icon 作用一样。某些情况,直接执行 pyinstaller xxx.py 时生成的 spec 中没有这个参数,需要手动添加,参数值就是图片路径的字符串。 |
|
COLL |
COLLECT 类的实例,用于创建输出目录。在 -F 模式下,是没有 COLLECT 实例的,并且所有的脚本、模块和二进制文件都包含在了最终生成的 exe 文件中。 |
以下的全局变量也可以在 spec
文件中使用 4:
全局变量 | 含义 |
---|---|
DISPATH |
相对于 dist 文件夹的相对路径,如果 --dispath 参数选项呗指定了,则使用被指定的参数值。 |
HOMEPATH |
pyinstaller 查找的绝对路径,一般是 python 解释器的 site-packages 文件夹的绝对路径。 |
SPEC |
在命令行中指定的 spec 文件路径。 |
SPECHPATH |
spec 文件的文件名,不包括文件类型后缀。 |
specnm |
spec 文件的文件名,不含文件类型后缀。 |
workpath |
相对于 build 文件夹的相对路径,如果 workpath=参数选项 呗指定了,这使用呗指定的值。 |
WARNFILE |
在 build 文件夹中警告文件的全路径。一般是 warn-myscript.txt 。 |
当命令行和
spec
中指定了相同的参数选项,那么命令行的参数选项会被忽略。
在对 python
项目进行打包修改 sepc
文件时,主要是以对 analysis
进行修改和配置为主。
以针对多脚本、多目录的 python
项目为例,一般而言对 spec
文件的配置都包含如下一些操作:
py
文件打包配置Analysis
的第一个参数(如 [script.py]
)为需要解析的 py
脚本。针对多目录多脚本的 python
项目,打包时需要将所有相关的 py
脚本文件都添加到 Analysis
类里,即第一个参数中,参考 7’ 8 中给出的例子。python
项目使用的相关文件,如模型配置文件、模型数据文件或者图标文件、文本文件等。Analysis
的 datas
。比如, ('data','data')
表示将 C:\\Users\\RYW\\Desktop\\test\\data
下的所有资源文件打包后放入打包结果路径下的 data
目录中,参考 7’ 8 中给出的例子。Hidden import
配置pyinstaller
在进行打包时,会解析打包的 python
文件,自动寻找 py
源文件的依赖模块。但是 pyinstaller
解析模块时可能会遗漏某些模块(not visible to the analysis phase
),造成打包后执行程序时出现类似 No Module named xxx
。这时我们就需要在 Analysis
下 hiddenimports
中加入遗漏的模块,参考 7’ 8 中给出的例子。RecursionError: maximum recursion depth exceeded
的错误,这可能是打包时出现了大量的递归超出了 python
预设的递归深度。因此需要在 spec
文件上添加递归深度的设置,设置一个足够大的值来保证打包的进行,即:import sys
sys.setrecursionlimit(5000)
运行时信息:
__file__
所有基于模块的使用到__file__
属性的代码,在代码运行时表示的是当前脚本的绝对路径,但是打包后就是当前模块的模块名(即文件名xxx.py
)。
sys.frozen
源码运行时没有这个属性,打包后的程序添加了这个属性,值为True。
sys._MEIPASS
源码运行时没有这个属性,打包后的程序添加了这个属性,表示程序运行的绝对路径。
对于-D
模式程序,表示的是这个exe
程序所在文件夹的绝对路径;
对于-F
模式程序,表示的是_MElxxxxxx
的文件夹绝对路径,_MElxxxxxx
为exe
解压后创建的临时运行环境的文件夹名称。对于exe
程序每一次运行来说,它是唯一的。sys.executable
代码运行时表示运行的解释器绝对路径,比如C:\Python36\python.exe
,在打包的程序中就是exe
程序文件的绝对路径,这个是用来定位用户运行该程序的真实位置。
sys.argv[0]
一般来说就是运行程序的绝对路径,但是在不同平台或者不同的方式启动程序时会有所不同,比如通过符号连接运行的sys.argv[0]
就是符号名称,而不是真实的程序路径。
打包生成的可执行文件过大的原因可能是因为 anaconda
环境下打包时引入了很多不必要的文件。
最简办法是用 pipenv
创建纯净环境。在纯净环境下,pip
安装程序所需要的第三方库,再打包程序 9。
pip install pipenv
pipenv --python 3.9
python
环境,注意 python 3.9
是利旧,利用旧有版本的 python
编译器,创建纯净的 python 3.9
虚拟环境;python
版本是 3.9
,pipenv --python 3.8
就会报错,是利旧的方式,而不是新增的方式,创建虚拟环境。virtualenv.py: error: no such option: --creator
,Failed to create virtual environment
,则先使用 pip install virtualenv --upgrade
,然后 virtualenv --version
确认 virtualenv
被成功安装和升级 10。pipenv shell
pipenv
的命令行pip install XXX
pipenv shell
下安装所要打包的程序用到的第三方库。pandas
、openpyxl
、以及打包所用的 pyinstaller
。pip list
pipenv shell
下使用 pip list
查看已有的库文件,可以看到,环境很纯净,只有第三方库及其依赖文件。pyinstaller -F xxx.py
打包。如果期间因为某些原因操作中断后找不到此前创建的
pipenv
虚拟环境,参考这里 11 找回原有虚拟环境。
对一个简单 .py
文件,当没有依赖的其他路径下的 .py
文件、没有间接依赖的其他包、没有依赖的资源文件时,可使用命令 pyinstaller –F xxx.py
,直接打包成一个 exe
文件。
使用命令 pyinstaller -c –F xxx.py
直接打包 xxx.py
文件。
一般而言,实际的项目往往是复杂的,或有许多依赖的其他路径下的 .py
文件,或有许多间接依赖的包,或有许多设计的资源文件。
针对多脚本的 python
项目可以通过修改 spec
文件的方法进行打包。
也可以通过核心命令
pyinstaller -F xxx.py -p py_dir
进行打包。但是在实际打包过程中或者即便打包成功后但是在执行可执行程序时,经常会遇到错误使得我们还是得去修改spec
文件重新打包执行程序。因此,本文直接使用修改spec
文件再根据spec
文件的方法对这几种类型的python
项目打包示例进行讲解,对于使用核心命令对多个程序进行打包的案例,可以参考这里 12,本文不再讲述。一般而言,大部分项目都会涉及多个脚本并包含数据资源文件。
由 spec
配置文件打包发布完毕后,必定会在 dist
中生成一个文件夹,里面不只有生成的exe
文件,还有许多其他的依赖文件。此模式下,通常使用命令 pyinstaller –D xxx.spec
进行发布。
基本步骤:
spec文件
pyi-makespec xxx.py
,执行后生成 xxx.spec
文件( xxx.py
是项目启动的入口文件);spec
文件中的内容spec
再次进行打包参考 1’ 8
当双击 exe
文件无法看到错误信息时,可尝试通过 cmd
进入对应目录后命令运行 xxx.exe
;
当打包成功,且中间没有发生任何警告提示,但是运行程序时提示某个模块找不到,可能是 --hidden-import=
的问题。对于不知道 hiddenimports
里面具体依赖的包有哪些,一个笨办法是,在 cmd
下执行xxx.exe
,根据提示的错误信息,逐一加上缺失的包 7。
杀毒软件可能会干预,最好打包发布前退出杀毒软件。
Unable to find "nltk_data" when adding binary and data files
这种错误发生在生成 exe
可执行程序时,会导致生成 exe
失败。这是 PyInstaller
的 hook
文件夹在处理 nltk
时出现这样的错误,参考 7。
XGBoostLibraryNotFound:Connot find XGBoost Library in …
的报错,参考 7。
FileNotFoundError:No such file or directory:…
(数据资源未能成功打包),参考 7。
无论在哪个目录下执行 pyinstaller
的命令,默认打包完成的文件或文件夹就在该目录。
路径最好为英文,没有中文字符。
脚本名称里应当没有特殊字符。
使用 utf-8
编码。
图标文件必须是正常格式,为 .ico
文件。
命令使用 pyinstaller
和 pyinstaller.exe
结果都是一样的。
参数的添加得在 pyinstaller
和 demo.py
文件中间,不能随意位置添加。
如果打包的代码中用到了静态文件,如图片和资源文件,需配置 spec
文件将相关文件复制到 dist
文件夹或其子文件夹下,否则 exe
文件会报找不到文件的错。
代码里导入 python
包最好使用 from * import *
的方式,而不是 import *
,可以节省打包后的文件大小。因为使用 import *
时,pyinstaller
打包时会将 python
解释器及项目中使用的整个模块复制过去,此时打出来的包就会很大 13。
当使用错误的参数去打包或打包到一半中断等等此类运行到一半没了的情况,会导致原来的 .py
文件变成一个 0 KB
的空文件,里面的代码会全部消失。因此,最好复制一份代码出来,用这个副本进行打包。
pygame
代码调试的时候要在结束时加 quit()
,不然程序会崩溃。
如果在 py
文件中用到了多进程,且在 windows
下编译需要加一行代码在开头,multiprocessing.freeze_support()
打包的时候要进入到能运行这个 .py
文件的虚拟环境中,不能在别的环境中对 .py
文件打包,不然打包的结果还是原来的环境,可能打包文件过大,或者引起缺失包等其他问题。
如果打包错误,可查看 build
里的 warn_script.txt
文档,里面详细记载了错误的原因。一般都是库丢失。
出现 IndexError: tuple index out of range
,出现这个是由于当前的 pyinstaller
版本不支持 python
的版本。解决方法是修改 pyinstaller
的版本,pip install pyinstaller == 适合你的版本
。
出现 ImportError: C extension: No module named ‘pandas._libs.tslibs.timedeltas’
,出现这个是由于代码中引入了 pandas
库但是使用 pyinstaller
打包时显示模块缺失。可以选择:
暂时忽略此模块,即打包时加上 --hidden-import=pandas._libs.tslibs.timedeltas
。或者,
在 python3
的安装路径下找到 Pyinstaller/hooks
的位置,如 C:\Python36\Lib\site-packages\PyInstaller\hooks
中新建文件 hook-pandas.py
并填写以下内容:
hiddenimports = [
# all your previous hidden imports
`pandas`: `pandas._libs.tslibs.timedeltas`
]
出现 module not found
警告时,可能并不需要对此进行特殊处理。只是 Pyinstaller
根据自身的逻辑去查找相应的模块,因为它们并不是跟你的最终程序有关的。
出现 File "c:\python36\lib\site-packages\PyInstaller\hooks\pre_safe_import_module\hook-setuptools.extern.six.moves.py", line 34, in pre_safe_import_module for real_module_name, six_module_name in real_to_six_module_name.items(): AttributeError: 'str' object has no attribute 'items'
, 解决方案是使用 pip install --upgrade setuptools
更新第三方库 setuptools
4。
由 pyinstaller
打包的 .py
项目,路径建议使用 os.path.join
,由此可以避免跨平台时由于路径表达不同导致的问题,且不会出现相对路径的问题 13。
为避免程序使用的图标无法显示、程序使用的关联文件无法关联,或者,程序使用的文件路径发生改变引入的问题,可以根据执行路径进行路径 "冻结“。参考这里 14。
如果本机安装了很多模块,使用 pyinstaller
打包的时候就会把已安装的模块都打包进去,从而导致打包生成的 exe
文件特别大。因此可以结合 pipenv
打包,参考这里 7。
在打包导入了 pandas
和 numpy
模块的 .py
文件时可能出现如下的报错:
按照提示先安装 openpyxl
,此外还需要注意版本冲突 15,再进行打包。
此时,可以通过修改 .spec
文件对 pandas
和 numpy
打包 16,或者使用 pyinstaller -F --hidden-import pandas --hidden-import numpy
命令进行打包 17。
在同一个目录下存在两个文件,一个 script.py
文件,一个 Config.json
文件。
Script.py
程序读写作为配置文件的 Config.json
文件。
.py
文件中的方法可以使用sys.argv[1]
以从控制台获取参数。
sys.argv[]
说白了就是一个从程序外部获取参数的桥梁,从外部取得的参数可以是多个,所以获得的是一个列表(list
),也就是说sys.argv
其实可以看作是一个列表,所以才能用[]
提取其中的元素。其第一个元素是程序本身,随后才依次是外部给予的参数 18。
Config.json
的文件内容如下,
"This is Config.json."
script.py
的内容如下,
import sys
print(sys.argv[0])
print(sys.argv[1])
项目的文件结构树如下:
为确保代码可运行,可在cmd控制台中实验,如下,
python script.py Config.json
确认可传参正常运行后,准备开始打包 exe
。
参考这里 19
script.py
所在目录,使用以下命令pyinstaller -F script.py
执行完毕后,若看到如下图所示的信息则表明打包成功:
执行完毕后,会有 dist
目录生成,dist
目录下有同名可执行文件 script.exe
,文件结构树如下:
exe
可正常使用。如下图所示:
或者,
该方法需要注意 script.exe
和 Config.json
文件的路径,否则极易出错。
script.py
所在目录,使用以下命令pyinstaller script.py
执行完毕后,若看到如下图所示的信息则表明打包成功:
执行完毕后,会有 dist
目录生成,dist
目录下有同名子文件夹 script
,同名子文件夹下有同名可执行文件 script.exe
,文件结构树如下:
script.spec
的内容,将 Config.json
添加到 data
中,表示将 script.py
所依赖的 Config.json
文件一同打包,如下所示:
3. 执行 pyinstaller script.spec
,依据 script.spec
中的内容将 Config.json
打包至 dist/script
目录下,若看到如下所示的信息则表示打包成功:
script.py
所在目录,使用以下命令先生成 script.spec
文件pyi-makespec script.py
执行完毕后,若看到如下图所示的信息则表明 .spec
文件生成:
项目的文件结构树如下:
script.spec
的 datas
,以将程序所在同目录下的 Config.json
文件拷贝至打包后的程序所在根目录下,下面的内容可参考这里 20。
script.py
可以接收 Config.json
作为参数传入并且正常运行。在 pycharm
终端或者 cmd
控制台输入:python script.py Config.json
如果可以看到正常的运行日志的输出,这说明可以从 cmd
控制台向 .py
文件中传递参数。下一步就是要打包成 exe
文件了。
script.py
所在的目录,打包 script.py
:pyinstaller –F C:\Users\Desktop\TEST\script.py
结果如下所示,则表明打包成 exe
成功:
6098 INFO: Writing RT_GROUP_ICON 0 resource with 104 bytes
6099 INFO: Writing RT_ICON 1 resource with 3752 bytes
6099 INFO: Writing RT_ICON 2 resource with 2216 bytes
6099 INFO: Writing RT_ICON 3 resource with 1384 bytes
6099 INFO: Writing RT_ICON 4 resource with 37019 bytes
6099 INFO: Writing RT_ICON 5 resource with 9640 bytes
6099 INFO: Writing RT_ICON 6 resource with 4264 bytes
6099 INFO: Writing RT_ICON 7 resource with 1128 bytes
6103 INFO: Copying 0 resources to EXE
6104 INFO: Emedding manifest in EXE
6104 INFO: Updating manifest in C:\Users\Desktop\TEST\dist\script.exe.notanexecutable
6105 INFO: Updating resource type 24 name 1 language 0
6109 INFO: Appending PKG archive to EXE
7934 INFO: Building EXE from EXE-00.toc completed successfully.
打包结束后在当前文件夹生成 dist
和 build
两个文件夹和 xxx.spec
文件,其中 dist
文件夹中便是执行文件,里面会有个 xxx.exe
。
检验打包后可不可以使用,可以在 Pycharm
的终端或者 cmd
窗口验证结果:
C:\Users\Desktop\TEST\dist\script.exe C:\Users\Desktop\TEST\Config.json
若运行结果中无报错,则该打包后的 exe
文件可成功运行。
需要注意地是:
cmd
命令行传进的参数全是字符串类型的;cmd
,所以不需要写明文件地址,如果不是在文件所在的文件夹下,则需要加上文件路径。cmd
获取参数的,对于不需要获取参数的也同样适用,只是在 cmd
中不需要写参数而已。与 tkinter
相关的示例
linux python封装成exe,pyinstaller打包python文件成exe(原理.安装.问题) ↩︎ ↩︎
python打包含有参数传递的exe程序 ↩︎ ↩︎ ↩︎ ↩︎
python打包成可执行文件app(Mac版) ↩︎
Python三方库:PyInstaller(exe程序打包) ↩︎ ↩︎ ↩︎ ↩︎
pyinstaller打包exe程序步骤和添加依赖文件方法 ↩︎ ↩︎
pyinstaller打包外置文件并使用 ↩︎
利用pyinstaller将python项目脚本打包成可执行文件 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
使用pyinstaller将python项目打包发布为exe可执行文件 - 探索字符串 ↩︎ ↩︎ ↩︎ ↩︎
解决pyinstaller打包文件过大的问题(Anaconda) ↩︎
Installing Python environment and packages error , virtualenv.py: error: no such option: --seeder (IDFGH-6840) ↩︎
关于python:pycharm-添加已存在的-pipenv-虚拟环境解释器 ↩︎
【Python】 —— pyinstaller 打包多个 py 文件为一个 exe ↩︎
linux 打包文件夹_Python利用PyInstaller打包 ↩︎ ↩︎
pyinstaller 打包程序的相对路径问题 ↩︎
pyinstaller打包程序包含openpyxl库问题解决 ↩︎
PyInstaller and Pandas ↩︎
pyinstaller打包exe,无法包含pandas、numpy解决办法 ↩︎
python命令行参数sys.argv的使用 ↩︎
python打包运行在Linux上 ↩︎
如何用pyinstaller将需要传参数的Python文件生成exe文件 ↩︎