1.概述
需求:當(dāng)我們用python寫好一個(gè)單機(jī)版小程序炮温,想發(fā)布在網(wǎng)上或給朋友使用時(shí)袭祟,我們希望能將程序和python環(huán)境一起打包成一個(gè)可執(zhí)行文件雙擊運(yùn)行即可挑社,網(wǎng)友下載后直接運(yùn)行不需要再安裝python環(huán)境和相關(guān)依賴蟹漓。
pyinstaller是一個(gè)能將Python程序轉(zhuǎn)換成單個(gè)可執(zhí)行文件的程序索抓, 操作系統(tǒng)支持Windows, Linux, Mac OS X, Solaris和AIX碳蛋。并且很多包都支持開箱即用胚泌,不依賴環(huán)境。
2.打包
此處我們以win10+python3.5+virtualenv環(huán)境為例演示打包過程
先準(zhǔn)備一個(gè)寫好的python小程序肃弟,我們用Flask將結(jié)巴分詞的cut分詞展示在網(wǎng)頁(yè)上源碼下載
在一個(gè)空目錄中創(chuàng)建一個(gè)virtualenv的虛擬環(huán)境玷室,并安裝應(yīng)用的相關(guān)依賴:
D:\workspace\Python\test\test-pyinstaller>virtualenv env
Using base prefix 'c:\\soft\\python\\python3'
New python executable in D:\workspace\Python\test\test-pyinstaller\env\Scripts\python.exe
Installing setuptools, pip, wheel...done.
D:\workspace\Python\test\test-pyinstaller>env\Scripts\activate
(env) D:\workspace\Python\test\test-pyinstaller>pip install Flask
Collecting Flask
Using cached Flask-0.12.2-py2.py3-none-any.whl
Collecting itsdangerous>=0.21 (from Flask)
Collecting Werkzeug>=0.7 (from Flask)
Using cached Werkzeug-0.12.2-py2.py3-none-any.whl
Collecting click>=2.0 (from Flask)
Using cached click-6.7-py2.py3-none-any.whl
Collecting Jinja2>=2.4 (from Flask)
Using cached Jinja2-2.9.6-py2.py3-none-any.whl
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->Flask)
Installing collected packages: itsdangerous, Werkzeug, click, MarkupSafe, Jinja2, Flask
Successfully installed Flask-0.12.2 Jinja2-2.9.6 MarkupSafe-1.0 Werkzeug-0.12.2 click-6.7 itsdangerous-0.24
(env) D:\workspace\Python\test\test-pyinstaller>pip install jieba
Collecting jieba
Installing collected packages: jieba
Successfully installed jieba-0.38
(env) D:\workspace\Python\test\test-pyinstaller>
在虛擬環(huán)境中安裝打包需要的依賴:
在windows環(huán)境中會(huì)依賴win32api,所以需要下載pywin32笤受,在此處下載對(duì)應(yīng)python版本的pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/穷缤,下載好后用easy_install安裝;安裝完成后再安裝pyinstaller箩兽,此處從git上安裝最新版本的pyinstaller
(env) D:\workspace\Python\test\test-pyinstaller>easy_install pywin32-221.win-amd64-py3.5.exe
(env) D:\workspace\Python\test\test-pyinstaller>pip install git+https://github.com/pyinstaller/pyinstaller
環(huán)境準(zhǔn)備完畢津肛,我們項(xiàng)目中的目錄結(jié)構(gòu)如下:
pyinstaller打包命令如下:
pyinstaller [-F] [-w] [-p 模塊] [-i logo.icon] 程序入口文件路徑
參數(shù)說明:
-F 表示生成單個(gè)可執(zhí)行文件
-w 表示去掉控制臺(tái)窗口,這在GUI界面時(shí)非常有用汗贫。不過如果是命令行程序的話那就把這個(gè)選項(xiàng)刪除吧身坐!
-p 表示你自己自定義需要加載的類路徑,一般情況下用不到
-i 表示可執(zhí)行文件的圖標(biāo)
在程序目錄執(zhí)行如下命令進(jìn)行打包:
(env) D:\workspace\Python\test\test-pyinstaller>pyinstaller app.py
打包完成后目錄結(jié)構(gòu)如下:
在dist目錄中會(huì)包含一個(gè)與可執(zhí)行文件同名的目錄芳绩,目錄里面會(huì)有一個(gè)與可執(zhí)行文件同名的.exe文件掀亥,這個(gè)文件及為可執(zhí)行文件。
若我們的程序依賴一些靜態(tài)資源我們需要將靜態(tài)資源拷貝到可執(zhí)行文件所在目錄妥色,我們上面的程序需要將模板文件與結(jié)巴分詞的詞典拷貝進(jìn)去搪花。
然后雙擊app.exe啟動(dòng)flask應(yīng)用,在網(wǎng)頁(yè)訪問查看效果:
3.踩過的坑
安裝pyinstaller時(shí)直接使用pip install pyinstaller,打包時(shí)會(huì)報(bào)一些錯(cuò)誤撮竿,所以直接安裝git上的最新版
如我們程序中使用了多進(jìn)程multiprocessing吮便,我們需要?jiǎng)?chuàng)建一個(gè)模塊內(nèi)容如下:
# Module multiprocessing is organized differently in Python 3.4+
try:
# Python 3.4+
if sys.platform.startswith('win'):
import multiprocessing.popen_spawn_win32 as forking
else:
import multiprocessing.popen_fork as forking
except ImportError:
import multiprocessing.forking as forking
if sys.platform.startswith('win'):
# First define a modified version of Popen.
class _Popen(forking.Popen):
def __init__(self, *args, **kw):
if hasattr(sys, 'frozen'):
# We have to set original _MEIPASS2 value from sys._MEIPASS
# to get --onefile mode working.
os.putenv('_MEIPASS2', sys._MEIPASS)
try:
super(_Popen, self).__init__(*args, **kw)
finally:
if hasattr(sys, 'frozen'):
# On some platforms (e.g. AIX) 'os.unsetenv()' is not
# available. In those cases we cannot delete the variable
# but only set it to the empty string. The bootloader
# can handle this case.
if hasattr(os, 'unsetenv'):
os.unsetenv('_MEIPASS2')
else:
os.putenv('_MEIPASS2', '')
# Second override 'Popen' class with our modified version.
forking.Popen = _Popen
然后在我們的main方法的最前面調(diào)用如下代碼:
import multiprocessing
multiprocessing.freeze_support()
4.參考
使用PyInstaller打包Python程序
pyinstaller的庫(kù)導(dǎo)入和多進(jìn)程打包問題