天天看點

pyinstaller介紹和簡單使用

打包的好處:不需要安裝python即可直接運作,将py程式和依賴包打到一個二進制檔案裡,不需要安裝任何依賴,支援多平台,适合分發;

常用的打包工具:

pyinstaller,cx_Freeze(支援多平台)

py2exe,pynsist(隻支援win平台)

py2app(支援macos平台)

bbFreeze(隻支援win,linux平台上的py2版本)

osnap(隻支援win和mac平台)

打包工具官方網站及狀态

http://www.pyinstaller.org/  # 持續更新中

https://cx-freeze.readthedocs.io/en/latest/  # 持續更新中

https://github.com/py2exe/py2exe  # 近3個月未更新

https://pynsist.readthedocs.io/en/latest/  # 近2個月未更新

https://github.com/ronaldoussoren/py2pp  # 持續更新中

https://github.com/schmir/bbfreeze  # 廢棄

https://github.com/jamesabel/osnap  # 廢棄

pyinstaller介紹

是一個跨平台的打包程式,目前已支援win|linux|macos|freebsd|solaris|aix等多個平台的可執行程式打包,配置簡單;

pip install pyinstaller  # python3.6+

pyinstaller --version  # 4.5.1

vim pyinstallerDemo.py

pyinstaller -D ./pyinstallerDemo.py  # dist/pyinstallDemo/pyinstallerDemo.exe,單目錄(多檔案)格式;若代碼中有引入外部檔案如base_dir=os.path.dirname(os.path.abspath(__file__)),在多檔案這種形式下是可以正常運作的,但在“單檔案格式”中會報錯(運作時會在使用者家目錄下建立臨時目錄,運作結束會删除臨時目錄),要用base_dir=os.path.dirname(os.path.realpath(sys.argv[0]))

pyinstaller -F ./pyinstallerDemo.py  # 單檔案格式;如果在運作時需要檢視程式中的異常資訊,可先打開win console再輸入腳本的完整路徑 - 再運作,而輕按兩下打開的console在異常時會直接退出

-n NAME.exe  # 自定義目标可執行檔案名

yum -y install python38-devel  # linux平台

注,目标目錄下檔案名和目錄名不能相同,否則會報錯

pyinstaller原理:

查找檔案-查找子產品,在腳本裡找所有import語句,然後根據import語句後面的子產品名找到對應的子產品位置,再疊代查找,直到找到所有需要的子產品;

查找檔案-查找py解釋器,找到你的開發環境設定的py解釋器路徑,然後将py解釋器檔案及所需的依賴檔案都複制過來;

查找檔案-查找時需要注意的問題,pyinstaller是根據import語句來查找子產品,而在py中除了import語句以外,還有另外的方式可導入子產品:__import__()函數、importlib.import_module(),如果遇到這種情況會看到報錯No module found,解決辦法:改為import語句導入子產品|在打包時通過指令行選項指定子產品路徑|編輯spec檔案告訴pyinstaller需要額外導入哪些子產品;

兩種格式:

單目錄格式,預設,适合大型項目,即把所有的檔案和依賴打包到一個目錄裡去,然後在目錄下可執行打包好的exe檔案,這種模式有2個優點(非常适合排錯,因為在目錄裡你可以清楚的看到包含了哪些子產品;在更新代碼時,隻需要更新重新打包後的exe檔案,而單目錄格式下這個檔案非常小,是以在大規模分發時非常有優勢);劣勢(在大量依賴中找到需要的那個可執行檔案比較麻煩;不小心會删掉目錄中的任意檔案會導緻無法運作);

單檔案格式,适合腳本或小項目,是把所有依賴和py腳本打包到一個exe檔案裡,實際使用時直接輕按兩下這個exe檔案或/path/xxx.exe調用,單檔案模式執行時,它首先會在機器上建立一個臨時目錄,然後使用内部打包的py解釋器在這個臨時目錄下啟動一個臨時py環境,在這個環境裡執行py腳本,同時在打包的檔案内部查找打包進來的子產品,還會查找需要的檔案,有時還需要解壓打包的檔案,是以單個檔案模式可能會比單目錄格式要慢些;優勢(隻有單個可執行檔案、使用簡單友善;不擔心删除單個檔案導緻無法執行的情況);劣勢(單個打封包件在依賴多時,會非常大,需要使用壓縮措施;建立的臨時目錄在程式被殺死時不會自動删除,是以在應用頻繁崩潰時,會大量消耗硬碟空間,需要手動清理);

使用spec檔案:

在單目錄格式或單檔案格式,都會生成一個.spec檔案,這個檔案是用來告訴pyinstaller怎麼處理你的腳本,pyinstaller通過執行這個spec檔案裡的内容來建構app,可了解為linux裡打rpm包時使用的spec檔案;

在大部分場景下,基本上都不需要主動編寫或修改這個檔案,實際應用場景有:需要在app裡打包資料檔案(如包含sqlite資料庫檔案);需要從其他位置包含.dll或.so檔案;需要添加py運作時參數到可執行檔案裡;

注,單檔案格式使用外部檔案,官方提供解決方案:

if getattr(sys, 'frozen', False):

    base_dir = os.path.dirname(sys.executable)

else:

    base_dir = os.path.dirname(os.path.abspath(__file__))

注,打包時-導入子產品問題:

正常的from utils import db導入沒問題,db.get_conn();

但如果是動态導入子產品的代碼時,是無法找到關聯的包,如

import importlib

db = importlib.import_module('utils.db')

db.get_conn()

解決辦法:

a = Analysis(  # 在.spec檔案中指定,并在打包時需指定.spec檔案如pyinstaller -F demo.spec

    hiddenimports=[

        'utils.db',

    ],

)

注,在使用多線程時,win平台下需在__main__()的第一行加上:

multiprocessing.freeze_support()

繼續閱讀