pyinstaller介绍
pyinstaller是一个python的第三方库,它能够在Windows、Linux、 Mac OS 等操作系统下将 Python 源文件打包,通过对源文件打包, Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个独立文件方便传递和管理。在Windows上使用就打包成.exe文件。在Mac上使用就打包成mac app。
打包成exe
需要借助工具pyinstaller
pip install pyinstaller
我们安装在了虚拟环境下
这个工具在Windows中打的包,只能在Windows中使用,在Mac中打的包只能在Mac中使用
Python代码需要在Python解释器中运行,这对于一些用户来说可能不太方便。因此,将Python代码打包成可执行文件(exe)是一种很好的解决方案。
一般python脚本想要在Windows上面点击执行,需要打包成.exe文件
注意事项:
- 支持mac、win(如果Windows中高版本不行买酒安装低版本的python)。
- 配合虚拟环境打包。
- 项目crm
- 环境crm
- python.exe
- Scripts
- pip.exe
- pyinstaller.exe
- Lib
- site-package
- requests
- flask
- pyinstaller
激活虚拟环境(pycharm打开终端默认激活)
环境crm/Scripts/pip.exe install pyinstaller
cd 项目目录
环境crm/Scripts/pyinstaller …
1.1 多文件 -D 这样是创建一个文件夹
里面包含这个项目依赖的包和库等,还不能删
pyinstaller -D app.py
我们写个测试脚本
到脚本所在目录执行
pyinstaller -D .\pyinstalltext.py
看到这个执行结束
我们会看到在当前目录下会生成一个dist和build的文件夹
dist文件夹下,就会生成我们需要的exe执行文件
我们在Windows终端,进入到该exe所在文件夹,可以直接执行
但是这样就比较乱,很多文件夹和文件,而且不能删除
如果我们只把可执行程序copy到其他地方执行
双击执行,直接闪退。无法执行
在终端执行报错,找不到执行模块
此时如果想要程序在其他地方执行,需要把dist目录下的所有文件都copy走,然后才能执行。很不方便
我们在想,如果能把所有依赖什么的都打包成一个文件多好。pyinstaller也是可以实现的
1.2 单文件,打包时用 -F 此时我们打包只会生成一个文件
pyinstaller -F app.py
我们先将上面打包的文件都删除
防止干扰
然后再执行
此时dist目录下只生成一个可执行文件
为了防止我们在Windows中点击完程序,执行完就立马退出了,我么可以设置个手动退出提示
#为了防止我们程序执行完就退出,我们设置个手动退出提示
input(‘按回车退出>>’) #占着进程不退出
重新打包
此时打包的程序,我们可以复制到任何地方执行,而不必依赖打包时创建的文件
比如我们把可执行程序copy到桌面
可以像其他Windows程序一样双击执行
按回车退出程序
打包成一个文件,并不代表只是单独的一个文件,当我们执行程序时,也会临时生成多个文件,只是执行完就删除了,我们无感知
打包成一个文件,也会遇到一些问题。当我们的脚本有依赖的文件时,我们打成一个包。点击执行程序会报文件找不到的错误
如果是打包成多个文件,我们可以把依赖的文件放到打包后程序的文件夹下,没问题
但是如果打包成单个文件,就算我们把依赖文件放到可程序文件目录下,他也找不到。这是因为单个文件执行时会把依赖文件解压后放到临时目录
而这个临时目录,不在程序的当前目录。所以我们把依赖文件放到当前目录下也找不到
- 多文件打包,不会报错。
- 单文件打包,报错。
为什么会报错?加载&解析到临时目录问题。
案例:
比如程序需要读取这个文件中的内容
程序中读取文件
该程序自己单独运行没问题
我们将程序打包成多文件,然后将依赖文件放到打包的项目目录下
此时,双击运行可执行程序也不会报错
但是老版本中,我们如果打包成单文件,依然把依赖文件放在可执行文件同级目录下执行,就会报错找不到依赖文件
如果报错解决方案:
借助sys.argv[0] 找到可执行文件名,然后根据os.path.dirname()找到改文件所在目录
#获取可执行文件所在目录 BASE_DIR = os.path.dirname(os.path.abspath(sys.argv[0])) print(BASE_DIR) with open(os.path.join(BASE_DIR,'info.txt'),'r',encoding='utf-8') as f1: data = f1.read()
新版本不拼接目录也不再报错
实现代码
import time import os import sys if getattr(sys, 'frozen', False): # pyinstaller打开 BASE_DIR = os.path.dirname(sys.executable) else: # py文件路径 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) print("----环境使用xxx系统----") with open(os.path.join(BASE_DIR, "account.txt"), mode='r', encoding='utf-8') as f: data = f.read().strip() print(data) time.sleep(5)
1.3 关于模块
动态加载不同目录
但是,如果遇到那种动态导入模块的代码时,他是无法找到关联的包。
import time import importlib print("----环境使用xxx系统----") # from utils import card # card.get_number() card = importlib.import_module("utils.card") v1 = card.get_number() print(v1) time.sleep(5)
此时我们打包时,就不再加-F 或 -D 而是直接执行.spec文件
案例,定义一目录,下不同py文件下有同样函数名称
import importlib name = input('请输入模块名称:') path_string = f'utils.{name}' #动态导入 md = importlib.import_module(path_string) res = md.func(11,22) print(res)
此时如果再按之前方式打包,程序运行时就会找不到模块
解决这样的问题,就要借助.spec里面有个隐式导入的配置
我们把要导入的模块路径放在这个列表里面,再次打包时,我们不能再通过py文件来运行了,否则会重新生成这个.spec文件。而是基于这个.spec文件进行打包
我们把其他打包时生成的文件删掉,重新打包
pyinstaller pyinstalltext.spec
此时再执行就不报错了
打包成单文件的可执行文件,把其他依赖的utils目录下的文件删了,也可以正常执行
也可指定生成程序的名称
生成的可执行程序和.spec文件都是我们指定的名称
1.4 程序图标
在打包时,加入 -i 参数可以展示图标(内部需要依赖pillow模块将图片转换为icon)
pip install pillow
打带图标的包
pyinstaller -F pyinstalltext.py -i lingge.jpg
1.5 PyInstaller 支持的常用选项
-h,–help 查看该模块的帮助信息
-F,-onefile 产生单个的可执行文件
-D,–onedir 产生一个目录(包含多个文件)作为可执行程序
-a,–ascii 不包含 Unicode 字符集支持
-d,–debug 产生 debug 版本的可执行文件
-w,–windowed,–noconsolc 指定程序运行时不显示命令行窗口(仅对 Windows 有效)
-c,–nowindowed,–console 指定使用命令行窗口运行程序(仅对 Windows 有效)
-o DIR,–out=DIR 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件
-p DIR,–path=DIR 设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径
-n NAME,–name=NAME 指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字