前言
python打包成exe程序的方法有不少,但最常用的还是pyinstaller,打包python程序主要是为了给那些不懂python的人用的,而且如果是像pyqt一类的图形界面程序,打包一下也会变得更易用。
安装
pip install pyinstaller
使用
使用pyinstaller就是一条命令行的事,命令的格式如下:
pyinstaller [选项] xxx.py
其中选项可以用命令 pyinstaller -h查看,常用命令如下:
选项 | 功能 |
-h, --help | 帮助 |
–distpath DIR | 生成临时文件的位置,默认在当前目录的build文件下 |
–clean | 清除生成的文件(重新生成前先清除) |
-D, --onedir | 打包成一个包含exe程序的文件夹 |
-F, --onefile | 打包成一个独立的exe程序(运行起来会慢很多) |
–hidden-import MODULENAME | 有些依赖包是动态导入的需手动导入告诉pyinstaller |
-d {all,imports,bootloader,noarchive} | 生成debug版本 |
-w, --windowed, --noconsole | 隐藏命令行窗口 |
-i <FILE.ico or FILE.exe,ID or FILE.icns> | 为程序添加ico图标 |
-n NAME, --name NAME | 为exe程序指定名称,默认和py程序名一样 |
打包完成后会生成三个文件(夹):build,dist,以及一个.spec文件,这个文件记录你的打包参数,可以直接在里面修改参数,然后执行以下命令直接打包,对于依赖复杂的程序这么做更方便,毕竟谁也不想每次打包都输那么长的命令行。
pyinstaller xxx.spec
至于spec文件具体怎么用参考官方文档。
一些坑
打包pyqt程序
虽然理论上程序打包很简单,但实际上可能会遇到各种问题,在打包pyqt程序时如果用的是动态导入ui文件,那么就得加上 –hidden-import PySide2.QtXml 并且把ui文件也一同放入exe文件夹内,因为程序并不会打包ui文件;如果程序用到了什么像图标,图片之类的静态文件,也需要都放到exe文件夹下。
1、单个程序还是文件夹
程序打包默认打包成一个文件夹,使用==-F==参数可以打包成一个单独的exe程序,但经测试,单独一个程序启动速度起码慢了10倍不止,所以建议还是默认文件夹方式,但文件夹太乱了怎么办,可以采取后面的方法整理一下。
另外我发现我的程序在打包成一个独立的exe的情况下,隐藏命令行窗口的话,程序中间有个命令无法正常运行,但是打包成文件夹就可以正常运行,由此可见打包成文件夹的容错率更大。
2、隐藏命令行窗口
- 如果你是gui程序自然不希望出现命令行,那么加上-w参数就行了。
- 另外隐藏命令行的话,就无法查看报错信息,那么只能在程序里捕捉异常然后通过gui的方法把错误显示出来。但这种错误显示通常不能获取多少有用信息,只是给用户看的。
- 有时候程序隐藏了窗口,但运行时总有黑黑的命令行窗口不时的闪现出来,网上查找到的弹窗多半是因为程序中引用了os.system引起的,但其实任何可能调用命令行窗口的程序命令都有可能导致弹窗。
- 比如我的程序因为黑窗口闪现太快肉眼无法捕捉,为了看清这个窗口究竟是什么,我利用录屏一帧帧查看发现是ffmpeg.exe的窗口,好吧,我的程序的pydub库的确用到了它,但怎么让它消失呢,我找到了一篇参考文章。因为pydub库的源码是直接使用subprocess调用ffmpeg.exe和ffprobe.exe的,只需要在audio_segment.py和utils.py文件中调用subprocess.Popen()时指定参数 shell=True, stdin=subprocess.PIPE 即可。
pyinstaller 打包命令(只适用于我开发的工具)
pyinstaller --hidden-import pandas -F main.py 或
python -m pyinstaller --hidden-import pandas -F main.py
# 用此命令可以避免,没有pymysql模块:
python -m PyInstaller --hidden-import pandas --hidden-import pymysql -F main.py
# 取消dos窗口:
pyinstaller -F mycode.py --noconsole
pyinstaller -F -w mycode.py
PyInstaller --hidden-import pandas --hidden-import pymysql -F main.py --noconsole
# 为打包的exe设置logo:
pyinstaller -F -i test.ico test.py