前言

大家好,作为一名python资深爱好者,写完的python想给别人用,不会写代码的小姐姐电脑上又没有环境,可咋办呢?

这时候,pyinstaller就开始表演了。Python生成可执行文件(exe or Ubuntu下bash文件),本文记录笔者初次使用pyinstaller踩的所有坑。

安装pyinstaller

作为一名python爱好者,conda虚拟环境相信你已经很清楚了,下面直入主题:

1
2
$ conda activate your_envs  # 激活虚拟环境
$ pip install pyinstaller # 安装pyinstallerb包

或者使用离线安装,安装方式:

Pyinstaller离线包链接中选择最新版win64位的下载即可,然后安装方式同上:先激活你的虚拟环境,然后pip install 把你刚下载好的离线文件拖到这个pip install 后面回车即可。

Pyinstaller 生成exe(无参数版)

Pyintaller的语法在Windows,MacOS和Ubuntu的语法相同,但是在Windows下打包的应用只能在Windows下使用,MacOS和Ubuntu同理。

简易版

首先我们有一个写好的脚本test.py,然后打包指令为

1
$ pyinstaller -F test.py

会在你的python根下生成一个builddist文件夹还有一个spec文件,你生成的exe就在dist里边。双击即可运行。

进阶版

下面来看一下pyinstaller的参数

-h 该模块的help信息
-F 生成一个可执行文件
-D 生成一个目录(包含多个文件)作为可执行文件
-w 运行exe时,不显示命令行窗口(仅对Windows有效)
-i 该参数后跟可执行文件的icon图标路径
–distpath 该参数后跟可执行文件的路径
-n 该参数后跟可执行文件的新名字

我的常用生成指令:

1
$ pyinstaller -i apple.ico -F test.py

参数解释:-i 是生成exe文件的图标,后边参数即为图标的路径;-F生成==一个==exe文件,如果用-D的话,会生成一个文件夹,包含exe和依赖的dll等文件;最后是要打包的python脚本名称;如果运行exe后,不想显示cmd窗口的话,加上-w即可。

Pyinstaller 生成exe(带参数版)

相信写好的脚本都有输入输出,那么现在分两种方法进行介绍

相对路径传参

首先在python脚本中获取当前文件路径,然后倒推同根下或者上一级文件,前提是首先把你的输入路径写死,比如

1
2
3
4
project
|---- test.exe
|---- input_dir
|---- output_dir

那么你的python就可以通过os.getcwd()获取project的路径,然后向子路径寻找你的input;或者通过os.path.dirname(os.path.abspath(__file__))来获取project的路径,然后告诉你的小姐姐说:你的文件都要放在这个input下才行~
然后:

1
$ pyinstaller -F test.py

指定路径传参

指定路径通过sys.argv[]来传递test.py的参数,如下

1
2
3
4
5
6
7
8
# test.py
import sys

def add(a, b):
c = a + b
return c
if __name__ == '__main__':
add(sys.argv[1], sys.argv[2])

在终端运行时使用python test.py 1 2即可。
然后:

1
$ pyinstaller -F test.py

继续:

1
2
$ cd 你的test.exe路径下
$ test.exe 1 2

这样即可通过指定参数完成传递。

Pyinstaller打包多个py文件为一个exe文件

打包的文件可能包含多个py脚本和一些其他类型文件,如xml, ui, pth等等。因为需要调用的文件较多,建议将所有的非py脚本放在根目录下新建文件夹中去调用,所有的py脚本放在根目录下,这样看起来会十分的整洁,笔者亲身经历。前提要保证放在文件夹中的非py文件可以正确被调用哦。直接上栗子🌰:
你的目录长这个样子:

1
2
3
4
5
6
7
8
project
|---- test.py
|---- func1.py
|---- func2.py
|---- dir
|------ file

# test.py为你要封装的文件,func1.py和func2.py为test.py需要调用的py脚本,dir中的文件为py脚本需要调用的非py类文件

你需要这样运行即可:

1
2
3
4
5
$ cd project
$ conda activate your_env
$ pyinstaller -w -D test.py func-1.py func-2.py
# 最新测试
# pyinstaller -w -D test.py 也可以

如果想给exe添加icon,可以第三节中进阶版中的参数,是一样的。

使用NSIS把文件夹打包成windows的安装包

NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 系统下安装程序制作程序。它提供了安装、卸载、系统设置、文件解压缩等功能。

  1. 下载安装NSIS,NSIS下载地址
  2. 把封装好的文件压缩成zip
  3. 打开NSIS,点击第一个模块Complier中的Installer based on .ZIP file
  4. 点击open选择第二步压缩好的 zip文件
  5. Installer Name为项目名字,只有在双击安装包的安装界面显示在title上,最终安装名字还是zip的名字,所以可以不改,步骤五可略过
  6. 点击Generate,在zip的同根下会生成最终的安装包

这样操作的好处是减少了传输成本,笔者亲测,打包好的文件为309M,zip为115M,而这样的安装包只有87M。如果打包的文件越大,这么处理的传输效率更高。

踩坑和遇到的问题

  1. 程序要严谨,在程序内部使用相对路径,main主函数中的接口可以通过argv外传参数;也可以使用相对路径。建议使用第二种,毕竟给小姐姐的exe约傻瓜越好。
  2. exe文件是可以直接拖入激活虚拟环境的cmd中进行debug的。
  3. pyinstaller的版本一定要保证最新,否则运行exe后,小黑框还是原样,什么也不显示,但是拖入cmd中debug是没毛病的。笔者就被这个坑了好久才弄明白。
  4. 双击exe后,小黑框闪了一下就没了,可以在程序末尾加上time.sleep(5),表示5s后关闭程序;或者添加os.system('pause'),表示程序暂停,按任意键继续。。。
  5. ico图标可以通过度娘ico生成器进行生成
  6. 被调用的脚本需要拷贝到dist中打包好的文件夹中,否则可能导致调用失败
  7. 运行exe后如果提示缺少文件,就去anaconda下搜索缺少的依赖文件,复制到exe同根下即可。
  8. windows建议使用新建虚拟环境进行打包,新建的envs中只install你的python脚本中import的包即可,这样打包文件很小。笔者做了测试,使用你本来的虚拟环境会把原来的包都打在一块,有300M左右,而新建的envs打包只有50M;Linux系统可以随意安装python库,封装的时候会按照python导入的包去封装,不会将环境内所有package打包。

小结

到这里就成功啦,快把你的exe给小姐姐吧,让她更加膜拜你。
如果还有任何疑问,欢迎随时评论,每天回复😊