文章目录
- 一、描述
- 安装
- 资料
- 二、打包配置
- 控制台
- spec规范文文件
- 三、入门
- 常用参数
- One-Folder模式和One-File模式
- 调出控制台窗口与否
- add-data
- 三、进阶
- execute多个文件
- 自定义模块的no module问题
- python库no module的问题
一、描述
- 第三方库,要自己安装。
- 将Python程序打包成标准的可执行文件,这些文件可以在没有安装Python的计算机上运行。
- win、linux、mac
安装
pip install pyinstaller
二、打包配置
均等同。
控制台
控制台中:
pyinstaller [options] script
pyinstaller my_script.py --onefile --windowed
把控制台中的命令写成python文件让其执行,到时候
python 文件.py
。
import PyInstaller.__main__
PyInstaller.__main__.run([
'my_script.py',
'--onefile',
'--windowed'
])
spec规范文文件
将控制台中的命令写成规范文文件,到时候pyinstaller [options] 规范文文件.spec
。
PS:从规范文件构建时,命令行中options指定的参数会和规范文件内指定的参数起冲突:
- 大部分将被忽略,参数只按照规范文件中的选项配置。
- 只有以下命令行的参数起作用:
--upx-dir=
,--distpath=
,--workpath=
,--noconfirm
,--ascii
,--clean
(▲)。
三、入门
常用参数
参数 options | 作用 |
| 显示帮助 |
| 显示程序版本信息 |
| 命名(默认值:第一个脚本的名称) |
| 清理 PyInstaller cache,在构建之前删除临时文件 |
| One-Folder模式(默认) |
| One-File模式 |
| 【win和mac特定】调出控制台窗口(默认)。 |
| 【win和mac特定】不调出控制台窗口,即静默模式。 |
| 【win和mac特定】 ①FILE.ico:将该图标应用于Windows可执行文件。 ②FILE.exe,ID,从exe中提取ID为ID的图标。 ③FILE.icns:将图标应用于Mac OS X上的.app捆绑包。 ④使用“ NONE”不应用任何图标,从而使操作系统显示某些默认设置。 ⑤默认(不写这个参数时):用PyInstaller的图标 |
| win下用 SRC是文件打包前所在路径,DEST是在打包程序中的目录安排。 一般是txt、图片、pdf、配置文件之类的 |
| 一般是dll、so |
|
One-Folder模式和One-File模式
打包get.py
,产生三个文件(夹):
-
get.spec
:用于pyinstaller打包的规格文件。不用关心。 -
build
:如同大多数编译器一样的构建过程文件夹。不用关心。 -
dist
:结果产物,你关心的。
One-Folder模式:
pyinstaller get.py
这就是那种发过来一个zip文件夹,你解压一下运行其中exe的程序。
正如解压,把这个get文件夹压缩成zip,给别人就行。
单独把exe移出文件夹运行,失败。
One-File模式:
pyinstaller -F get.py
本质是把那么多文件都整合到了exe中,运行时再解压出来。
运行的时候会解压到临时文件夹,所以运行时启动会因为这个原因慢一点点,之后运行就和One-Floder一样快。
调出控制台窗口与否
- 如
print()
之类的I/O信息会输出到控制台窗口上。 - 静默模式下,程序该运行的还是会好好运行的。用途可以是,程序不需要你在控制台上输入,你不想看到控制台的输出信息时,静默后台执行的程序。
- 你有GUI的图形化界面,自然不需要控制台窗口。
add-data
One-Folder
# 3.py
import os,sys
with open('hhhhhh.txt', 'r') as fp:
print(fp.readlines())
pyinstaller --add-data ./hhhhhh.txt:. 3.py
因为确实存在于目录下,所以直接就能获取
One-File
因为One-File中是解压到临时文件夹中下,而不是当前文件夹下,自然找不到。
所以解决办法就是:使用绝对路径=临时文件夹目录+相对路径。
# 3.py
from os import path
# 主文件解压后的绝对路径
print('__file__=',__file__)
# 主文件解压后所在目录的绝对路径
parentPath = path.dirname(__file__)
print('parentPath=',parentPath)
toolPath = path.dirname(path.join(parentPath,'.'))
print('toolPath=',toolPath)
# 打印看一下path下的各文件、文件夹情况
from os import listdir
for _ in listdir(path):
print(_)
# 绝对路径+相对路径
with open(path.join(toolPath,'hhhhhh.txt'),'r') as fp:
print(fp.readlines())
pyinstaller --add-data ./hhhhhh.txt:. 3.py -F
三、进阶
execute多个文件
# 这样表示你顺序执行多个py文件
pyinstaller [options] script1 script2 …
# 1.py
if __name__ == "__main__":
print('it is 1.py')
# 2.py
if __name__ == "__main__":
print('it is 2.py')
pyinstaller 1.py 2.py
打包出来都是以其为主程序来执行。a.py
和b.py
谁先谁后,只关乎打包文件的名字采用第一个文件,谁先运行罢了。
所以写模块文件的时候,不要在模块文件中写if __name__ == "__main__":
的测试部分。
自定义模块的no module问题
因为按照第二种修改sys.path
的写法来调用模块b.py
,pyinstaller就找不到,你得加入pyinstaller -p=/home/admin/pro/tool
模块的目录名,非常麻烦。
而按照这种python 调用其他文件函数或类的“主程序与模块写法”,pyinstaller能轻易找到tool模块,直接pyinstaller a.py
就成了。
PS:而且这种写法from tool.b import *
/import tool.b
,pyinstaller看到tool.b
,会保留了这种模块文件的结构。
`
|-- a.py
`-- tool
`-- b.py
而修改sys.path
的写法,虽然能运行,但是pyinstaller丢失了这种模块结构,b.py
和a.py
在同一个目录下。
`
|-- a.py
`-- b.py
这个可关乎到模块文件访问资源文件的问题。比如,tool/init.py
要访问src/setting.ini
,第二步airtest_project的路径
就会出现问题。
# init.py文件中
print('__file__', __file__) # init.py的路径
pro_dir_path = path.abspath(path.join(path.dirname(__file__), '..')) # airtest_project的路径
print('pro_dir_path=', pro_dir_path)
setting_path = path.abspath(path.join(pro_dir_path, 'src/setting.ini')) # airtest_project的路径/src/setting.ini
print('setting_path=', setting_path)
python库no module的问题
pyinstaller并不是支持所有的库的,因为有些库写法很糟糕,它无法识别到。
所以要手动打包进去(使用One-Fold
模式)。
把缺失的库直接复制到这里。
ok。