最詳細的Python打包工具:Pyinstaller實戰指南,如絲滑般體驗
寫了個吊炸天的Python專案,把我和左手相處的時間都賠上了。但出於版權考慮,我不太想讓使用方直接用我的程式碼,畢竟Python程式碼給出去,就真的收不回來了。
想給客戶演示的時候,不想那麼墨跡的開啟dos cmd 或者 terminal ,然後執行 python app.py 這樣的命令列。最好是客戶雙擊,完事兒。就像有人在那自己動一樣……
PyInstaller 來了,他就是這麼一款幫助我們把整個專案完整打包的工具。目前已經相容Py3.7,以及 Mac App 和 Windows Exe。
文件: https://pyinstaller.readthedo...
先說下,這篇文章有別於網上那坨安裝、打包的草包,這次是真核!
1. 安裝
這個很簡單,直接 pip install pyinstaller 就好。
:warning:注意了:你要編譯成exe,建議你省心點的在windows上用pyinstaller,如果你要mac app的,那就用mac編譯。
我今天就以windows為例
2. 簡單使用
這個也很簡單,網上一抓一大把,我這裡就不贅述了,無非就是那麼幾個命令:
pyinstaller -F 專案主檔案(或者是單一指令碼)
3. 引數說明
-F,打包所有的依賴包在一個exe中,包括你自己的模組、內建模組以及第三方模組。
-c,如果你是命令列視窗,就要加上這個引數。
-w,視窗程式,比如你用了PyQt。
4. 高階用法:配置檔案
.spec,這個檔案非常重要,我們可以通過編輯這個檔案來打包我們的專案,類似DockerFile。
我給大家貼一個我的:
# -*- mode: python -*- block_cipher = None a = Analysis(['C:\\app\\main.py'], pathex=['C:\\'], binaries=[], datas=[ ('C:\\data\\input\\builtin\\*.xlsx', '.\\data\\input\\builtin\\'), ('C:\\data\\input\\*.xlsx', '.\\data\\input\\'), ('C:\\data\\output\\', '.\\data\\output\\'), ('C:\\log\\', '.\\log\\'), ('C:\\app\\db\\', '.\\app\\db\\') ], hiddenimports=['numpy', 'pandas'], ... ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, ... )
這其實就是一個python檔案,只不過字尾是spec罷了。
.spec一共會有4個物件,分別是:Analysis、PYZ、EXE、COLLECT。
Analysis用處最多,一個個解釋:
- 第一個引數,是指定我們整個專案的主程式,也就是我們的入口檔案。
- pathex,就是我們的工作目錄
- datas,存放我們的資料。
好了,說到這裡就要好好說一說這個Pyinstaller的工作流程了。當我們雙擊編譯好的exe後,他是會建立一個臨時目錄,把所有需要用的包都解壓到那裡,然後執行。執行完畢後,臨時資料夾就消失了。
這和我們有什麼關係呢?想一下,如果你的專案中需要去讀取某些檔案,甚至是使用者的輸入引數,怎麼辦?打包出來的exe 是沒有辦法通過直接指定引數,類似:python main.py --input=*.xlsx 來讀取檔案的,因為我之前說了,在執行的時候會把專案解壓到一個臨時目錄,所以原來專案中寫好的相對路徑也不管用。
為此,我們需要把host上的實際檔案給copy到那個臨時目錄下,所以這個datas的作用就是這個,我的檔案中,我把host下的 C:\data\input\builtin*.xlsx檔案都copy到臨時目錄的 data\input\builtin 下面。
hiddenimports ,繼續說下去,PyInstaller有時候無法偵察到全部的依賴包,怎麼辦?我們可以在這個後面加,把PyInstaller編譯出來的exe在執行的時候報的缺少模組給寫裡面。
:warning:注意了: pandas 和 numpy 有個很奇怪的地方,就是引用了 pandas 的地方,如果沒有引用 numpy ,就會報錯。所以你可以在主入口上面加一個 import numpy 。
:warning:注意了:直接 import numpy 還是會報錯。怎麼辦?在 import numpy 下面加 import numpy.core._dtype_ctypes
5. 臨時目錄
那剛剛說的臨時目錄在程式碼裡怎麼處理呢,如果程式碼中還是老樣子處理相對路徑,一定是找不到的。
官方文件中給出了這麼一段:
Your app should run in a bundle exactly as it does when run from source. However, you may need to learn at run-time whether the app is running from source, or is “frozen” (bundled).
import sys if getattr( sys, 'frozen', False ) : # running in a bundle basedir = sys._MEIPASS else : # running live
所以在你的專案中,如果有配置檔案的話,就在那裡加上這一段,然後在bundle中新增你的新路徑,else還是你的老程式碼。
這個 sys._MEIPASS 是個特殊的值,是在Pyinstaller打包的時候才會新增的臨時變數,通過這個變數我們可以獲取到在執行exe時候的臨時目錄。
這對程式碼的改動是最小的。
6. 編譯打包
最後,我們執行 python xxx.spec 就好了。打包的可執行檔案會在dist裡,build中是一些打包時候需要的檔案。
輸出中最後有 successfully 字樣,就算成功了。他也會告訴你,exe出現在哪個位置。
當然不是說這樣就萬無一失了,別人也可以反編譯你的exe,所以我們可以在打包的時候用Cython去編譯一次,把混淆過的程式碼打包。這樣的話難度就增加了,同時再加上mac地址繫結,這裡就有多種思路了。
相信大家在學python的時候肯定會遇到很多難題,以及對於新技術的追求,這裡推薦一下我們的Python學習扣qun:784758214,這裡是python學習者聚集地!!同時,自己是一名高階python開發工程師,從基礎的python指令碼到web開發、爬蟲、django、資料探勘等,零基礎到專案實戰的資料都有整理。送給每一位python的小夥伴!每日分享一些學習的方法和需要注意的小細節
走進:python技術分享交流
