Python 打包工具之 pyinstaller

什么是 pyinstaller

PyInstaller 可以将 Python 程序打包成的独立的可执行文件。它通过读取编写的 Python 代码并分析代码在执行时需要的每一个模块和库。通过收集所有这些文件的副本及 Python 解释器,将其放在一个文件夹里,或者生成一个单独的可执行文件。

pyinstaller 优缺点

优点:

  • 打包快,并且操作简单。
  • 跨平台

缺点:

  • 性能差,执行的效率会比较低。
  • pyinstaller 捆绑编译的 Python 脚本(.pyc文件)。 原则上可以对这些进行反编译以揭示你的代码逻辑。

还有关于单文件打包的弊端,如下图:

00.png

来源于知乎 (https://www.zhihu.com/question/48776632/answer/2336654649) @韦易笑的回答。

pyinstaller 安装

1
> pip install pyinstaller

校验是否安装成功:

1
2
> pyinstaller --version
5.11.0

pyinstaller 打包

使用一个实际的项目来演示如何打包,项目地址在 QtComMate,基于 pyqt6 的一个串口工具。

项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├─docs
│ ├─images
│ └─translations
└─src
│ config.py
│ main.py
│ main.ui
│ requirements.txt
│ resources_rc.py
│ serialport.py
│ serialport_combobox.py
│ Ui_main.py
└─Resources
├─icon
│ main.ico
├─img
├─sty
└─translations

上述我省略了一些无关紧要的文件,可以看出主程序是 ./src/main.py 图标在 ./src/Resources/icon/main.ico 中。

确认了主入口和图标位置后,开始打包,输入下述命令:

非单文件:

1
> pyinstaller -D -w -i ./src/Resources/icon/main.ico ./src/main.py

单文件:

1
> pyinstaller -F -w -i ./src/Resources/icon/main.ico ./src/main.py

等待命令执行完,执行完毕后,会在当前目录下生成 dist 文件夹,这样就打包成功了。

01.png

02.png

简单运行下,

00.gif

打包命令各参数解析:

1
> pyinstaller -D -w -i .\src\Resources\icon\main.ico .\src\main.py
  • -w:不显示控制台窗口
  • -i:可执行文件的图标路径。
  • -D:创建一个包含可执行文件的单文件夹。
  • -F:创建一个单文件可执行文件。

如果要了解其他的命令参数可以输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> pyinstaller -h
usage: pyinstaller [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME] [--add-data <SRC;DEST or SRC:DEST>] [--add-binary <SRC;DEST or SRC:DEST>] [-p DIR] [--hidden-import MODULENAME]
[--collect-submodules MODULENAME] [--collect-data MODULENAME] [--collect-binaries MODULENAME] [--collect-all MODULENAME] [--copy-metadata PACKAGENAME]
[--recursive-copy-metadata PACKAGENAME] [--additional-hooks-dir HOOKSPATH] [--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES] [--splash IMAGE_FILE]
[-d {all,imports,bootloader,noarchive}] [--python-option PYTHON_OPTION] [-s] [--noupx] [--upx-exclude FILE] [-c] [-w]
[-i <FILE.ico or FILE.exe,ID or FILE.icns or Image or "NONE">] [--disable-windowed-traceback] [--version-file FILE] [-m <FILE or XML>] [--no-embed-manifest]
[-r RESOURCE] [--uac-admin] [--uac-uiaccess] [--win-private-assemblies] [--win-no-prefer-redirects] [--argv-emulation]
[--osx-bundle-identifier BUNDLE_IDENTIFIER] [--target-architecture ARCH] [--codesign-identity IDENTITY] [--osx-entitlements-file FILENAME]
[--runtime-tmpdir PATH] [--bootloader-ignore-signals] [--distpath DIR] [--workpath WORKPATH] [-y] [--upx-dir UPX_DIR] [-a] [--clean] [--log-level LEVEL]
scriptname [scriptname ...]

positional arguments:
scriptname Name of scriptfiles to be processed or exactly one .spec file. If a .spec file is specified, most options are unnecessary and are ignored.

optional arguments:
-h, --help show this help message and exit
-v, --version Show program version info and exit.
....

结语

如果单纯打包玩玩的话,可以使用 pyinstaller + pipenv 虚拟环境打包的方式,这样不会导致不需要的依赖也被打包,这里我就不多说了,我还是更推荐 Nuitka 的打包方法。