1、前言
Python虽好,但是平时我们写的代码都是.py脚本文件,必须要在Python环境下 才可以运行。如果一台电脑没有安装Python是无法运行我们的程序的。当然你也可以选择随身携带安装包。 不过终究是有些麻烦。那么有没有什么办法,能把我们编写的Python代码转换成exe文件呢?这样不管到哪, 只要能打开exe就可以运行我们的程序。当然,办法是有的。网上一搜就有py2exe、pyinstaller等包可以实现 我们想要的这个功能。这里我们选择pyinstaller。
2、Pyinstaller的使用
(1)安装PyInstaller
PyInstaller官网地址在这,点击进入。其官网首页非常简洁。截图如下:
官网的“快速开始”建议我们直接通过pip安装。然后在控制台转移到脚本所在的目录,直接”pyinstaller yourprogram.py” 即可生成exe文件。十分方便。
首先打开控制台,输入”pip install pyinstaller”,然后就是静待安装。
(2)使用PyInstaller
为了测试它的功能到底好不好用,这里特意挑选了一段稍微复杂点的代码,如下:
# coding=utf-8
import numpy as np
import cv2
def nothing(x):
pass
path = raw_input("Input the path of image:\n")
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
threshold = 128
result = gray
cv2.namedWindow("Threshold Test")
cv2.createTrackbar('Threshold', 'Threshold Test', threshold, 255, nothing)
cv2.createTrackbar('0:Off 1:On', 'Threshold Test', 1, 1, nothing)
while 1:
cv2.imshow('Threshold Test', result)
k = cv2.waitKey(1) & 0xff
if k == 27:
break
threshold = cv2.getTrackbarPos('Threshold', 'Threshold Test')
s = cv2.getTrackbarPos('0:Off 1:On', 'Threshold Test')
if s == 0:
result = gray
else:
ret, result = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)
cv2.destroyAllWindows()
这段代码引用了比较大的OpenCV函数库。而且有控制台部分,也有图形界面部分。算是比较全的覆盖了 可能用到的情况。这段代码的功能是首先用户在控制台输入一张图片的地址,然后弹出一个二值化界面。 在该界面上有一个滑动条,可以拖动改变二值化阈值,另一个可以打开或关闭二值化效果。演示图如下:
下面就把这个脚本文件变成一个独立运行的exe。首先打开控制台,然后切换到该文件所在的目录下。 注意首先要切换盘符,直接输入”D:”或其它即可换到该盘下。然后再输入”cd D:\output"换到该目录下。 直接cd是换不到D盘的。
换到该目录后,输入”pyinstaller threshold.py”,按回车等待即可。生成时间取决于代码多少和复杂程度。 完成后如下图所示。
再次打开我们的目录,可以发现多了几个东西。
我们想要的exe可执行文件就在dist文件夹中。所以我们只需要将整个这个文件夹随着携带,就可以在没有Python 的机器上运行我们的程序了。而至于其它的build文件夹和spec文件则是生成过程中产生的文件,我们可以不用管它。
可以看到PyInstaller把我们引用的OpenCV库原封不动地包进来了,此外还有其它一些与界面有关的东西。 打开dist中的threshold.exe便可以成功运行程序,如下所示。
如图可以看到,首先打开了一个黑框框要我们输入图片路径,然后弹出了界面。和我们预想的一样,完美达成目标。
(3)只打包一个exe软件
上面其实我们已经实现了我们的目标。但有时我们不想拷给别人一大堆东西。只有一个exe文件。这样也很好办,我们 只需要在生成的时候,在文件名前面加上”-F”这个参数即可。
输入”pyinstaller -F threshold.py”。输出结果就只有一个exe了。
对比之前的那个exe和这个exe,可以发现这个更大了(29.4 MB),而上面的那个exe只有3.36 MB。但是整个dist文件夹的 大小是75.9 MB。所以从最终结果上来说,这一种方法更省空间。
但经过测试,它虽然省空间,也更方便(只有一个文件),但有点小问题,那就是程序启动稍微慢一点。同样的代码使用第一种 方式生成的exe是可以做到秒开的。而第二种方式的exe,经过记录,从打开到控制台弹出输入路径提示,平均在10秒左右。 个人认为可能的原因在于他把那么多文件压缩到了一个文件中,所以每次启动都要先解压缩那些文件到缓存中,而文件很多, 且压缩比应该也很高,必然导致很慢。如图所示是第一种方法生成的文件,有将近1000个文件。
所以说,鱼和熊掌不可兼得。如果说你不介意程序的启动速度或者说打开一次可以用很久,为了追求方便,那可以使用第二种方法。 如果你的程序需要经常打开,那还是建议你采用第一种方法吧。毕竟谁也不想每次开都浪费几秒钟的生命, 而且整个文件夹拷给别人也就是一个压缩包的事。个人猜测如果代码比较简单,生成的文件较少。那么可能两者差异应该不会很大。
此外PyInstaller还支持自定义图标等等,以上只是介绍了基本功能,更多功能可以去看官方的Manual,点击阅读。
3、踩坑记录
在后续使用过程中,发现了PyInstaller的一些弊端,在这里简单总结一下,并给出解决办法。
(1)不支持中文
首先是不支持中文,或者说不支持UTF-8编码。PyInstaller只支持ASCII编码。下面分别对各种含有中午的情况进行测试。
(2)生成路径含有中文
如生成路径为:D:\新建文件夹>pyinstaller 060302.py 。经过测试,生成路径含有中文名,是可以无法生成成功的。如下所示。
提示错误为ascii解码器无法识别路径索引为3的地方的’0xd0’字符。所以生成路径不能有中文。
(3)运行路径含有中文
根据上面的结论,生成路径不含中文,生成成功。然后我们将dist文件夹拷贝到一个中文路径下,如下图所示。
将dist拷贝到“测试”文件夹下,经过实验,发现是可以正常运行的。因此运行路径没有限制,可以含有中文。 同时可执行文件的名称也可随意修改,包含中文,因为文件名本身也是路径的一部分。路径可含中文,文件名 同样可以包含中文名。
(4)代码中含有中文
如果在注释中含有中文,需要在python文件第一行增加# coding=utf-8,否则python下就会报错。 如果在代码本身,如控制台提示语句中含有中文,同理添加utf-8。这样可以保证在python下不会出错。 但即使添加了这句话,在输出的控制台还是会有问题。因为PyInstaller输出的控制台程序不支持 中文。如下图所示,“请输入内容:”在这里变成乱码了。
又如需要对一个中文字符串进行处理时,spilt某个中文字符,在python下正常,但是转换后就会报错。 如果在控制台输入语句中含有中文,转成exe后可以支持输入中文。如下。
总结一下也就是说,如果想转成exe后还可以正常使用的话,那就不要在执行代码中包含中文字符,否则必然报错。
(5)控制台一闪而过
准确来说这不是PyInstaller的问题,而是Windows的问题。即使是用C/C++写的控制台程序,在Windows下运行结束后 都会自动退出。由于运行速度很快,给人的感觉就是一闪而过。在C++中解决这个问题是在代码最后加上一句system('pause'), 或是加上一句输入语句等待用户输入。所以在Python中的解决方法类似,也有两种解决办法。
增加输入语句
在代码的最后增加raw_input()即可,如果想更完善,可在括号的提示语句里写上”Press any key to exit.”。
raw_input("Press any key to exit.")
转为exe后在控制台下运行的效果如下:
完美实现了我们想要的效果。
强制暂停
类似于C++下面的system('pause'),这里导入os包,然后添加语句。
importosos.system('pause')
运行效果如下所示:
控制台不支持粘贴复制
在控制台中,发现不管是Ctrl+V还是鼠标右键都无法粘贴。其实并不是不支持,而是需要设置一下。 首先点击窗口左上角的图标,然后找到“属性”。
然后在打开的选项中找到“快速编辑模式”,选中并点击确定。这样就支持复制粘贴了。
注意在控制台中复制粘贴是通过鼠标右键完成的。选中某段文字单击右键即可复制,复制某段文字后, 回到控制台单击右键即可粘贴。
可能是某些库没有被打包进来
可以在CMD中看看软件报的错误,然后从Python/lib/site-packages找到该包复制到打包后的文件夹中即可。