欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python?pyinstaller打包exe最新完整圖文教程

 更新時間:2023年12月12日 09:26:50   作者:Python-ZZY  
pyinstaller是一個非常簡單的打包python的py文件的庫,下面這篇文章主要給大家介紹了關(guān)于Python?pyinstaller打包exe的相關(guān)資料,文中介紹的非常詳細,需要的朋友可以參考下

1 簡介

python提供了多種方法用于將普通的*.py程序文件打包成exe文件。exe文件即可執(zhí)行文件,打包后的*.exe應用不用依賴python,可以在他人的電腦上運行。

pyinstaller是一個第三方模塊,專用于python程序的exe打包。此外python還有一些別的方法進行打包,但是pyinstaller打包最強大而且好用。

pyinstaller的官網(wǎng)是:https://pyinstaller.org/

2 安裝

可以通過pip進行安裝。首先啟動cmd,輸入以下內(nèi)容后回車:

pip install pyinstaller

安裝完成后,驗證是否成功安裝:

pyinstaller --version

如果顯示找不到“pyinstaller”,請轉(zhuǎn)到最后一章“常見問題”

3 原理和打包效果

3.1 原理概述

在開始打包前,讀者有必要先了解pyinstaller的打包原理。

如果你只在乎打包結(jié)果而不在乎細節(jié),你可以跳過第3章,直接進入下面的打包環(huán)節(jié)。但是,當你打包時遇到問題時,還是建議你先把打包原理看完,可能你的問題會得到解決。

pyinstaller先讀取你需要打包的python文件,然后搜索其中使用的模塊,然后將所需的模塊以及Python解釋器放到一起,并通過一些操作構(gòu)建exe,最終形成你的應用程序。

3.2 搜索模塊

當然,在搜索模塊的時候必然會遇到一些問題。

pyinstaller只會搜索import語句,然后根據(jù)import得到的模塊再進行搜索。如果編程者使用了一些特殊的導入方式,比如使用__import__()函數(shù),使用importlib里面的導入函數(shù),那么pyinstaller很可能找不到你所需要的模塊。

這時,你可以通過參數(shù)來指定你所需要的模塊,也可以使用“鉤子”等等(這是后話)。

3.3 打包效果概述

pyinstaller打包后會形成一個文件夾或單個的exe(可以用參數(shù)指定)。但不論是哪一種情況,都會包含一個exe文件,用戶可以雙擊它運行該應用程序。

假如你要打包myscript.py,那么打包完成后運行這個myscript.exe,效果就是運行myscript.py后的效果。

默認情況下,打包會形成一個黑色的控制臺(cmd的樣子),也可以設置隱藏這個控制臺。

這個控制臺用于為python提供標準輸入(stdin),標準輸出(stdout),標準錯誤(stderr)。也就是說,這個控制臺上顯示了print函數(shù)的輸出,用于接收input函數(shù)的輸入,還會輸出python的異常。

如果你隱藏了這個控制臺,程序中的print就無法顯示(但是不會報錯),報錯信息也無法被用戶直接看到(pyinstaller有一些選項來控制顯示異常,后文詳解);需要注意的是,此時不能使用input,否則會報錯:

RuntimeError: input(): lost sys.stdin

python文件有一種后綴名*.pyw,這樣的程序執(zhí)行時默認會隱藏控制臺。如果將文件后綴命名為pyw,那么pyinstaller也會認為它隱藏了控制臺,不需要通過額外的選項來指定。

當你制作GUI程序的時候,最好選擇隱藏控制臺,來提升用戶體驗。 

打包后的文件可能會被反編譯(即通過exe文件得到原來的代碼),可以通過一些方法進行加密(后文詳解)。

3.4 打包成單個文件夾

下面介紹一下打包完成后形成的文件夾。

這個文件夾的名字是你提供的,一般是你要求打包的python文件的名稱。文件夾中包含一個exe文件,以及其他一些依賴文件(比如一些dll文件,可能還有你的應用所需要的圖片等素材)。你只需要將該文件夾壓縮就能發(fā)給別人運行了。

當你運行里面的exe文件后,pyinstaller其實只是啟動了解釋器,然后通過解釋器運行你的主程序。

優(yōu)點

打包成單個文件夾的形式便于調(diào)試,因為你可以清楚地看到pyinstaller將哪些模塊文件放到了文件夾中。

當你更改代碼,需要用戶更新應用時,只需要讓用戶對于部分內(nèi)容進行修改。如果你只修改了主程序,沒有使用多余的模塊,那么就只需要讓用戶替換里面的exe文件,而不用全部替換(因為更新前后使用的模塊是一致的,它們都以多文件的形式放到了文件夾中)。

單個文件夾的狀態(tài)下,程序的啟動速度和打包前差不多。

缺點

打包成單個的文件夾后,里面有大量的依賴文件,比如*.dll,還有一些文件夾。用戶從里面找出主程序exe可能需要一點時間。

3.5 打包成單個exe

單個exe模式下,pyinstaller只會生成一個單獨的exe文件,所有的依賴文件都會被壓縮到exe文件中。

和上面的文件夾模式類似,exe啟動后,pyinstaller也是通過調(diào)用python解釋器來運行主程序的。

優(yōu)點

打包成單個exe非常簡單,用戶只需要點擊exe文件就能運行,而無需在一大堆的依賴文件中找到exe文件。并且在經(jīng)過壓縮后,這個exe文件的文件大小會大大減小。

缺點

單個exe的啟動速度比較慢(通常會慢幾秒,且只是啟動時的速度,不是運行后的速度),這是因為pyinstaller會在這一段時間中將一些依賴文件寫入到一個臨時的文件夾(后文介紹該文件夾的調(diào)用方式)。

如果你希望添加一些附帶文件(比如使用說明README),你還需要額外新建文件夾并將其放進去。

4 打包

在了解相關(guān)原理后,下面正式進入打包環(huán)節(jié)。

本章介紹通過命令行參數(shù)進行打包,這種方式比較初級,適用于一般的打包方式。

4.1 基本語法

打包需要通過cmd進行,語法和大多數(shù)工具一樣。pyinstaller最簡單的打包方式是:

pyinstaller myscript.py

其中myscript.py是你想要打包的程序。

如果這一步提示找不到myscript.py,請檢查路徑是否正確;如這一步提示找不到pyinstaller工具,請參考最后一章“常見問題”。

如果直接傳遞文件名,pyinstaller會生成一個spec文件將一些打包參數(shù)放到里面,然后進行打包。打包完成后,你會在你的目錄下找到一個dist文件夾,里面存儲了打包后的結(jié)果。pyinstaller還會生成一個build文件夾并寫入一些日志信息。

當然,你也可以自己構(gòu)建一個*.spec文件(后文介紹),然后交給pyinstaller進行處理。

4.2 參數(shù)總覽

本節(jié)只是列舉并簡要介紹常用的參數(shù),并不過多展開,將在下面的部分對于一些重點參數(shù)舉例介紹。

如有不熟悉命令行參數(shù)的讀者可自行搜索,或者參考下面的介紹:

pyinstaller -D -i "icon.ico" myscript.py

調(diào)用命令時,首先給出工具名稱(比如上面的 pyinstaller ),然后提供相關(guān)參數(shù),有一些參數(shù)是可選的但不需要附帶任何值(比如上面的 -D ),有一些參數(shù)是必選的(比如上面的 myscript.py ),有一些參數(shù)需要附帶一個值(比如上面的 -i "icon.ico" )。其中有一些參數(shù)可以簡寫(比如 -i 就是 --icon 的簡寫)。

參數(shù)名描述
-D文件夾模式。在打包完成后生成一個文件夾,其中包含一個exe文件和若干依賴文件(詳見上文)。(默認)
-W單文件模式。在打包完成后只會生成一個單獨的exe文件(詳見上文)。
--add-data <SRC;DEST or SRC:DEST>

指定一個文件夾或文件(非二進制),將其嵌入到exe中。

--add-binary <SRC;DEST or SRC:DEST>和--add-data類似,不過指定的文件夾或文件是二進制的

-p DIR

--paths DIR

提供一個路徑進行搜索并且導入里面的模塊(不同的路徑使用路徑分隔符os.pathsep分隔開,或者多次使用這個參數(shù))。

這可以解決有時候第三方模塊找不到的問題。

--hidden-import MODULENAME

--hiddenimport MODULENAME

需要進行額外導入的模塊。當pyinstaller在程序中找不到一些模塊時,需要你額外指定。這個參數(shù)可以多次使用,可以解決一些模塊找不到的問題。

--splash IMAGE_FILE

添加一個啟動畫面(圖片文件)路徑,在程序運行前顯示指定的啟動圖片,起到加載提示的效果。
-c, --console, --nowindowed打包程序運行后出現(xiàn)一個黑色的控制臺窗口(默認)
-w, --windowed, --noconsole打包程序運行后隱藏控制臺窗口

-i <FILE.ico or FILE.exe,ID or FILE.icns or Image or "NONE">

--icon <FILE.ico or FILE.exe,ID or FILE.icns or Image or "NONE">

設置打包后exe程序的圖標(只能在Windows和macOS上使用)

--disable-windowed-traceback

禁用異常提示(只能在Windows和macOS上使用)

--help, -h打印pyinstaller的幫助信息并退出

4.3 隱藏控制臺窗口

下面是一個程序示例,將創(chuàng)建一個窗口并顯示一張圖片image.gif和一段提示。讀者無需了解其代碼細節(jié)。接下來將以這個程序為例進行一個簡單的打包示范。

import tkinter as tk
 
root = tk.Tk()
root.title("我的應用程序")
 
image = tk.PhotoImage(file="assets/image.gif")
label = tk.Label(root, text="你好,用戶!", image=image, compound="top")
label.pack()
 
root.mainloop()

下面是這個應用文件夾的文件層級結(jié)構(gòu):

- my_app
    - assets
        - image.gif
    - my_app_name.py

由于這是一個GUI應用,所以我選擇隱藏控制臺。打開cmd并進入程序文件所在的文件夾my_app,執(zhí)行:

pyinstaller -w my_app_name.py

接下來會出現(xiàn)若干個INFO提示,如果沒有錯誤,那么打包就成功了。

完成打包后,生成了build和dist文件夾,以及一個spec文件;dist文件夾包含打包的結(jié)果,build文件夾中是一些日志信息,spec文件里面是用于打包的配置信息。

接下來是重要的一步。由于打包時沒有綁定任何的資源文件,所以此時運行時會報錯,提示找不到image.gif。此時,應該把程序文件夾下的assets文件夾(參見上方的文件夾層級)復制到dist文件夾中的程序文件夾,和exe文件位于同一位置。

接下來,再試一下單文件模式的打包:

pyinstaller -w -F my_app_name.py

打包后,生成了一個單個的my_app_name.exe,而沒有其他文件。同樣也需要將assets文件夾復制到與該exe文件的同一位置。 

4.4 資源嵌入exe

經(jīng)常需要復制文件夾不僅麻煩,而且還無法防止里面的內(nèi)容被用戶修改。此時,我們可以使用pyinstaller的--add-data參數(shù),將assets文件夾里面的資源嵌入到exe文件中。

資源嵌入exe只在單文件模式下使用。文件夾模式下,資源文件夾不會嵌入到exe中,但是會被復制到exe所在的文件夾。

使用資源嵌入后,資源文件夾的路徑發(fā)生了變化,我們不能使用一般的相對路徑來調(diào)用assets這樣的內(nèi)嵌資源文件夾。

前面已經(jīng)講過,pyinstaller單文件模式下的exe啟動后,會將嵌入的資源文件放到一個臨時的文件夾中,這個文件夾的名字不是固定的,叫做_MEIxxxxx,其中xxxxx是隨機數(shù)。這個文件夾的路徑在打包后會被放到sys._MEIPASS這個變量里面,只需要調(diào)用sys._MEIPASS就可以獲得這個路徑文件夾。

于是,我們通過以下函數(shù)返回正確的路徑:

def get_path(relative_path):
    try:
        base_path = sys._MEIPASS # pyinstaller打包后的路徑
    except AttributeError:
        base_path = os.path.abspath(".") # 當前工作目錄的路徑
    return os.path.normpath(os.path.join(base_path, relative_path)) # 返回實際路徑

這個函數(shù)通過一個相對的路徑返回實際的絕對路徑。

需要注意:sys._MEIPASS這個屬性只有在打包成exe后才被創(chuàng)建,以py代碼執(zhí)行的時候這個屬性是不存在的,所以要通過try...except...代碼塊捕獲異常。如果不是pyinstaller模式,那么就使用py文件所在的文件夾的路徑作為基本路徑。這個函數(shù)可以直接拿來用(是一位叫做davidpendergast的大佬寫的)。

于是,我們將代碼改成這樣(省略了部分內(nèi)容):

...
import sys
import os
def get_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except AttributeError:
        base_path = os.path.abspath(".")
    return os.path.normpath(os.path.join(base_path, relative_path))
...
image = tk.PhotoImage(file=get_path("assets/image.gif"))
...

接下來進行打包:

pyinstaller -w -F --add-data assets;assets my_app_name.py

打包完成后會生成一個包含嵌入資源的單獨的exe,無需將資源文件放到同一文件夾下也能正常運行。

--add-data的參數(shù)由源文件名src和目標文件名dest組成。路徑的源文件名和目標文件名用文件分隔符進行分隔,源文件名是該文件或文件夾的原本的路徑,目標文件名是該文件夾嵌入到exe后的放入的文件夾名。

文件分隔符:在Windows系統(tǒng)上是分號,大部分unix系統(tǒng)上是冒號,可以通過os.pathsep來查看當前系統(tǒng)上的文件分隔符。例如:

>>> import os
>>> os.pathsep
';'

比如--add-data "assets;assets"就表示將原本assets里面的所有文件,放入打包后的assets文件夾。再比如--add-data "assets/*.mp3;music"表示將原本assets里面的所有mp3文件,放入打包后的music文件夾。 

4.5 更改圖標

打包完成后,默認的程序圖標是一個“蛇”形,但我們也可以進行更改。(根據(jù)官方文檔,該功能只能在Windows和macOS上使用)

--icon或-i參數(shù)用于設置圖標,該參數(shù)的值默認為"NONE",表示使用默認的圖標;也可以指定為一個*.ico格式的Windows圖標文件路徑;*.icns的Mac圖標文件路徑;或者一個其他圖片文件(需安裝pillow模塊,會通過pillow模塊將其轉(zhuǎn)換成標準的ico/icns格式)。

首先添加一個圖標文件。圖標文件在Windows上格式為*.ico,Mac上是*.icns。

- my_app
    - assets
        - image.gif
    - my_app_name.py
    - icon.ico

這個圖標文件其實放在哪里都可以,因為打包完成后其實它也相當于嵌入了exe。但為了方便,還是把它放到同一文件夾下比較好。

pyinstaller -i icon.ico my_app_name.py

為了方便看,之前設置的-w, -F這些選項都省略了。最后生成了一個圖標與icon.ico相一致的exe。

4.6 啟動畫面(閃屏)

pyinstaller單文件模式啟動速度較慢,所以可能需要一個啟動畫面(閃屏)進行過渡,提示用戶正在進行加載。這個啟動畫面可以是單張圖片,也可以是文本(默認情況下文本禁用,使用方式參見第5章)。

這個啟動畫面的實現(xiàn)基于Tcl/Tk(和python tkinter模塊一樣),打包時會附帶約1.5MB的額外文件來支持這個功能。

支持閃屏,需要先準備一張圖片,必須是PNG格式(如果你安裝了pillow模塊,可以用pillow模塊支持的其他格式)。然后,在打包時加上--splash參數(shù),并傳入圖片路徑。

pyinstaller --splash splash.png my_app_name.py

控制閃屏可以通過pyi_splash模塊,這個模塊和上一節(jié)的sys._MEIPASS屬性一樣,在沒有通過pyinstaller打包成exe后是不起作用的,所以必須帶上try...except...代碼。

pyi_splash.close()方法用于關(guān)閉閃屏。一般放在程序開頭即可,因為只要運行到程序開頭,說明pyinstaller的加載就基本完成了。

于是,在程序開頭部分添加以下代碼:

try:
    import pyi_splash
    pyi_splash.close()
except ImportError:
    pass

如果不進行關(guān)閉,那么閃屏將一直顯示。

打包后,閃屏效果如下。

至于pyi_splash還有一個update_text方法,用于顯示加載文本,將在第5章介紹。 

4.7 禁用異常提示

--disable-windowed-traceback參數(shù)用于禁用異常提示。如果不添加這個參數(shù),將會在非控制臺程序出錯時彈出一個窗口報告異常信息(注意:僅在隱藏控制臺模式下彈出異常報告窗口)。為了測試,我在代碼第一行添加了raise Exception,運行打包后的exe后效果如圖所示。

5 使用Spec文件

當你調(diào)用以上的打包方式時,會在腳本的文件夾下生成一個*.spec文件。

*.spec文件包含了打包需要使用的所有配置信息。直接在命令行中將*.spec文件路徑傳給pyinstaller,也可以進行打包。比如:

pyinstaller my_app_name.spec

(其中my_app_name.spec是根據(jù)my_app_name.py生成的Spec文件) 

這樣,當你多次打包同一個項目時,就無需每次都傳入那么多參數(shù),只需要傳入*.spec文件的路徑即可。

*.spec文件也比較好處理,直接使用python編輯器或記事本就能編輯。

5.1 生成Spec文件

使用pyi-makespec工具可以根據(jù)pyinstaller的命令行參數(shù)生成Spec文件。用法很簡單,在原先使用pyinstaller的打包命令中,把"pyinstaller"換成"pyi-makespec"就可以生成一個Spec文件。例如:

pyi-makespec -w -F --add-data assets;assets my_app_name.py

要更改Spec文件的生成路徑,可以指定參數(shù)--specpath。

如果報錯提示找不到pyi-makespec,轉(zhuǎn)到最后一章:常見問題。

當你使用*.spec文件進行pyinstaller打包時,大部分的打包參數(shù)都不可用,需要預先在*.spec文件中預先設定。

pyinstaller會將*.spec里面的內(nèi)容當做代碼執(zhí)行。單文件模式和文件夾模式的*.spec文件略有不同。

下面是一個*.spec文件(單文件模式打包)的例子。

# -*- mode: python ; coding: utf-8 -*-
 
block_cipher = None
 
a = Analysis(
    ['my_app_name.py'],
    pathex=[],
    binaries=[],
    datas=[('assets', 'assets')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
 
exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='my_app_name',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

下面是一個文件夾模式的*.spec文件的例子:

# -*- mode: python ; coding: utf-8 -*-
 
block_cipher = None
 
a = Analysis(
    ['my_app_name.py'],
    pathex=[],
    binaries=[],
    datas=[('assets', 'assets')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
 
exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='my_app_name',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)
coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='my_app_name',
)

這里面包含一些特殊的類,比如Analysis, PYZ, EXE等,文件夾模式下還多了一個COLLECT類。只有當pyinstaller運行時才會被定義,很顯然你不能在python解釋器中直接調(diào)用它們。 這些類的參數(shù)與pyinstaller的命令行參數(shù)并不一樣。

接下來將針對Spec文件中的這些對象進行介紹

5.2 Analysis對象

Analysis類包含一些分析信息,它分析模塊的導入以及一些依賴文件。

這個類的常用參數(shù)介紹如下。

參數(shù)名默認值描述(常用參數(shù))示例
scripts必選參數(shù),無默認值需要分析的文件路徑列表(一般就是需要打包的文件)["myscript.py"]
pathexNone需要額外進行分析模塊導入的文件(夾)路徑,包含命令行--path參數(shù)指定內(nèi)容["C:/Python310/Lib/site-packages", "C:/my_module]
binariesNone需要嵌入的二進制文件列表,包含命令行--add-binary參數(shù)指定內(nèi)容
datasNone需要嵌入的非二進制文件(夾),包含命令行--add-data參數(shù)指定內(nèi)容[("assets", "assets"), ("music/*.mp3", "music")]
hiddenimportNone需要額外導入的模塊列表["module1", "module2"]
hookspathNone鉤子文件路徑列表(鉤子文件用于配置一些模塊特殊的導入,后文詳解)
hooksconfigNone一個字典,包含鉤子的配置信息
excludesNone需要被忽略,不進行導入的模塊列表
runtime_hooksNone運行時的鉤子列表,指定為一系列文件名
noarchiveFalse如果設為True,則不會將源代碼放到一個存檔中進行存儲,而是作為多個單獨的文件

在完成分析后,需要將一些屬性傳遞給PYZ類。Analysis對象包含了以下屬性,你可以不必了解它們:

屬性名描述
scripts同參數(shù)中的scripts
pure需要一起打包的純python模塊
pathex同參數(shù)中的pathex
binaries同參數(shù)中的binaries
datas同參數(shù)中的datas

5.3 PYZ對象

完成分析后,將Analysis對象的一些屬性傳遞給PYZ類。PYZ相當于一個壓縮包,里面儲存了所有的依賴文件。

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

5.4 EXE對象

定義PYZ對象后,接下來需要定義EXE對象,也就是可執(zhí)行文件對象。

不同打包模式(單文件或文件夾)的EXE對象參數(shù)略有不同。其中常用參數(shù)如下:

參數(shù)默認值描述(常用參數(shù))示例
consoleTrue是否顯示控制臺,相當于命令行-w參數(shù)
disable_windowed_tracebackFalse是否禁用異常提示,相當于命令行--disable-windowed-traceback參數(shù)
nameNone可執(zhí)行文件的名稱。在Windows上會自動添加".exe"后綴"my_app_name"
iconNone可執(zhí)行文件的圖標路徑"icon.ico"

使用文件夾模式打包時還會有一個COLLECT對象,該對象用于創(chuàng)建文件夾。它有一個常用的關(guān)鍵字參數(shù)name,表示文件夾的名稱。

5.5 COLLECT對象(僅-D文件夾模式)

使用文件夾模式打包時還會有一個COLLECT對象,該對象用于創(chuàng)建文件夾。它有一個常用的關(guān)鍵字參數(shù)name,表示文件夾的名稱。

5.6 Bundle對象(僅macOS系統(tǒng))

如果你要在macOS上創(chuàng)建應用程序,且你的應用程序是無控制臺的,那么在exe構(gòu)建完成之后還需要添加一些代碼。

app = BUNDLE(exe,
             name='my_app_name.app',
             icon="icon.ico",
             bundle_identifier=None)

5.7 Splash對象

如果你想要在應用中添加啟動畫面(圖片和文本都可以),需要在Spec文件中額外添加一個Splash對象進行控制。

在分析完代碼后,創(chuàng)建Splash對象:

a = Analysis(...)
 
splash = Splash('splash.png',
                binaries=a.binaries,
                datas=a.datas,
                text_pos=(10, 50),
                text_size=12,
                text_color='black')

然后在EXE中綁定splash對象。注意:單文件模式和文件夾模式方式略有不同。

以下是單文件模式綁定splash對象的方法。

splash = Splash(...)
 
exe = EXE(pyz,
          a.scripts,
          splash,                   # <-- both, splash target
          splash.binaries,          # <-- and splash binaries
          ...)

以下是文件夾模式的方法。

splash = Splash(...)
 
exe = EXE(pyz,
          splash,                   # <-- splash target
          a.scripts,
          ...)
coll = COLLECT(exe,
               splash.binaries,     # <-- splash binaries
               ...)

下面介紹Splash對象的一些參數(shù)。注意:由于Splash窗口基于Tcl/Tk(和python tkinter一樣),所以里面有一些用法與Tcl/Tk(tkinter)的用法很像,但不重要。

參數(shù)默認值描述(常用參數(shù))示例
image_file必選參數(shù),無默認值圖片文件路徑,必須是PNG格式(如果你安裝了pillow模塊,可以用pillow模塊支持的其他格式)"splash.png"
binaries必選參數(shù),無默認值Analysis對象的binaries屬性
datas必選參數(shù),無默認值Analysis對象的datas屬性
text_posNone閃屏文本相對于閃屏圖片的顯示位置(是一個(x, y)元組,錨點為文本左下角)。如果不指定,則禁用文本顯示(500, 400)
text_size12文本大小
text_font"TkDefaultFont"文本使用的字體(必須是系統(tǒng)上安裝了的字體),如果不指定則設為系統(tǒng)默認字體"宋體"
text_color"black"文本顏色,顏色格式可以是顏色名稱字符串或者十六進制顏色字符串,如"#ff00ff"(注意:不支持(r, g, b)元組形式)
text_default"Initializing"默認顯示的文本(后面可以用pyi_splash.update_text來更新顯示的文本)"加載中……"
max_img_size(760, 480)最大閃屏圖片尺寸。如果超出尺寸,那么閃屏圖片將會被按縱橫比縮放,容納到該尺寸中??梢栽O為None不縮放
always_on_topTrue閃屏窗口是否置頂,如果置頂,其位于其他窗口之上
rundir"__splash"設置運行閃屏時,用于存放一些相關(guān)文件的文件夾名稱。使用這個參數(shù)主要是為了避免命名沖突,一般不會使用

下面就以一個示例來演示Splash的文本顯示。使用的代碼還是上一章節(jié)使用的。

在開頭添加以下代碼:

a = Analysis(...)
 
splash = Splash('splash.png',
                binaries=a.binaries,
                datas=a.datas,
                text_pos=(10, 50),
                text_size=12,
                text_color='black')

然后通過pyi-makespec生成對應的Spec文件:

pyi-makespec -w -F --add-data assets;assets --splash splash.png my_app_name.py

由于Splash的文本顯示只能在Spec文件中進行配置,所以我們先打開my_app_name.spec,將Splash對象的代碼進行修改,如下所示:

splash = Splash(
    'splash.png',
    binaries=a.binaries,
    datas=a.datas,
    text_pos=(30, 270),
    text_size=12,
    minify_script=True,
    always_on_top=True,
)

然后進行打包:

pyinstaller my_app_name.spec

運行效果如下:

可以看到,首先顯示文本被設定為加載的各個依賴文件,然后變成update_text中自己設定的加載內(nèi)容。

5.8 多包捆綁(打包多個exe)

有些產(chǎn)品由幾個不同的應用程序組成,每個應用程序可能依賴于一組通用的第三方庫,或者以其他方式共享一部分代碼。在打包這樣的產(chǎn)品時,如果單獨對待每個應用程序,將其與所有依賴項捆綁在一起,那就太可惜了,因為這意味著要存儲代碼和庫的副本。

此時,我們可以使用多包特性來捆綁一組可執(zhí)行應用程序,以便它們共享庫的單個副本。我們可以在單文件或單文件夾應用程序中做到這一點。

文件夾模式的多包捆綁

如果采用文件夾模式,想要捆綁多個應用程序,那么只需要共享一個COLLECT對象。假如有hello1.py, hello2.py,將這兩個應用進行捆綁,可以將它們的Spec文件進行一些組合。

首先通過pyi-makespec分別生成hello1.py, hello2.py的Spec文件。

然后將其中的Analysis, PYZ, EXE, Splash等對象分別以不同的變量名放入同一個Spec文件,然后將它們的COLLECT對象組合起來。

hello1_a = Analysis(['hello1.py'], ...)
hello1_pyz = PYZ(hello1_a.pure, hello1_a.zipped_data, ...)
hello1_exe = EXE(hello1_pyz,
          hello1_a.scripts, 
          ...)
 
hello2_a = Analysis(['hello2.py'], ...)
hello2_pyz = PYZ(hello2_a.pure, hello2_a.zipped_data, ...)
hello2_exe = EXE(hello2_pyz,
          hello2_a.scripts, 
          ...)
 
coll = COLLECT(hello1_exe,
               hello1_a.binaries,
               hello1_a.zipfiles,
               hello1_a.datas,
 
               hello2_exe,
               hello2_a.binaries,
               hello2_a.zipfiles,
               hello2_a.datas,
               ...
               name='hello')

這樣,將會生成同一個文件夾,該文件夾下包含兩個文件hello1.exe, hello2.exe。 它們共享一部分的依賴文件。

單文件模式的多包捆綁

單文件模式下,多包捆綁會生成多個單獨的exe,其中一個exe包含它們共有的依賴文件。

比如打包hello1.py和hello2.py,設置hello1包含共有的依賴文件,最后生成hello1.exe, hello2.exe。生成的hello1.exe由于包含兩個exe共有的依賴文件,其文件大小會大于hello2.exe。

運行hello1.exe時與單獨打包效果相同。但是運行hello2.exe時,它會在hello1.exe中搜索它需要的依賴文件,速度會稍慢。

如果將hello2.exe移動到別的地方,或者將hello1.exe改名,那么hello2.exe將無法運行,因為它找不到hello1.exe,從而無法找到所需的依賴文件。

以下是hello1.py和hello2.py兩個程序文件,將以它們?yōu)槔M行打包。

# hello1.py
while True:
    input("hello1")
 
# hello2.py
while True:
    input("hello2")

首先通過pyi-makespec生成對應的Spec文件。完成后,將兩個Spec文件的Analysis類匯總到一個文件中,并進行改名。

a1 = Analysis(
    ['hello1.py'],
    ...
)
 
a2 = Analysis(
    ['hello2.py'],
    ...
)

接下來在下面調(diào)用MERGE函數(shù)。這個函數(shù)會分析兩個文件中重復的依賴項,將結(jié)果放到分析類的dependencies屬性中。MERGE中位于第一個的程序?qū)灿械囊蕾図棥?/p>

MERGE((a1, "hello1", "hello1"), (a2, "hello2", "hello2"))

然后將兩個文件的ZIP和EXE進行匯總。匯總時需要額外向EXE類傳遞一個參數(shù)Analysis.dependencies。

pyz1 = PYZ(...)
exe1 = EXE(pyz1,
 
    a1.dependencies, ####
 
    a1.scripts, 
    a1.binaries,
    a1.zipfiles,
    a1.datas, ...)
 
pyz2 = PYZ(...)
exe2 = EXE(
    pyz2,
 
    a2.dependencies, ####
 
    a2.scripts,
    a2.binaries,
    a2.zipfiles,
    a2.datas, ...)

 保存文件,然后通過pyinstaller打包。

最后生成兩個文件,可以看到hello1.exe的文件大小比hello2.exe大了很多,這是由于hello1.exe中包含了它們共有的依賴庫。如果不使用多包捆綁,而是分別單獨進行打包,那么兩個文件的大小將都會超過5000KB。

6 鉤子

有一些特殊的模塊,它們存在一些特殊的依賴文件(比如ico, json等等)。而pyinstaller的導入分析無法檢測到這些特殊的依賴文件,這就導致運行后出現(xiàn)問題。于是,pyinstaller引入了“鉤子”。鉤子文件其實就是一種python文件,后綴名為*.py即可(和Spec文件的實質(zhì)是一樣的)。鉤子文件中指定了某個特殊模塊所需要的所有依賴文件。通過傳遞鉤子文件,pyinstaller就能找到那些“隱藏”的依賴文件。

雖然鉤子文件的作用也可以被--hiddenimport, --datas這些命令行參數(shù)替代,但是使用鉤子顯然更加方便。

pyinstaller有一些內(nèi)置的“鉤子”,提供了一些常用模塊的鉤子文件,它們包含Django, pickle, pyqt, scipy等等。

鉤子文件的常用命名格式是:hook-module.py(其中module是模塊名)。(當然你也可以按自己喜好命名)

6.1 鉤子文件中的全局變量

鉤子文件中可以包含以下全局變量(有一些變量可以不被寫在文件中):

屬性描述(常用屬性)示例
hiddenimports需要額外導入的模塊列表,相當于命令行--hidden-import參數(shù)["sys", "pygame.mixer"]
excludedimports需要被排除,不被自動導入的模塊列表(如果有一些模塊在其他地方被導入,那么仍然會導入它)["tkinter"]
datas需要備添加的非二進制文件或文件夾,相當于命令行--add-data參數(shù)[('/usr/share/icons/education_*.png', 'assets') ]
binaries需要備添加的二進制文件,相當于命令行--add-binary參數(shù)

以下是一個鉤子文件的示例:

hiddenimports = ["re", "os"]
datas = [("assets", "assets)]

6.2 PyInstaller.utils.hooks

pyinstaller提供了一些方法用于鉤子文件的制作。這些方法位于PyInstaller.utils.hooks模塊。首先需要在鉤子文件導入該模塊。(注意pyinstaller的P和I是大寫的,這是pyinstaller作為模塊時的名稱)

import PyInstaller.utils.hooks as hooks

下面介紹該模塊中的常用函數(shù)。

is_module_satisfies(requirements, version=None, version_attr='__version__')

檢驗模塊版本是否達到requirements的要求,返回一個布爾值。關(guān)于requirements的相關(guān)格式,詳見PEP 440。version_attr參數(shù)指定該模塊中版本屬性的名稱,默認是"__version__"。

下面是一些requirements的例子:

"pygame >= 2.2.1dev1" # 大于2.1.1dev1版本的pygame模塊
"PIL == 2.9.*"    # 版本以2.9.開頭的PIL模塊
"sphinx >= 1.3.1; sqlalchemy != 0.6" # 同時滿足兩個要求

collect_submodules(package, filter=<function <lambda>>, on_error='warn once')

返回一個模塊的所有子模塊。filter是一個篩選函數(shù),接收模塊名作為參數(shù),返回一個布爾值表示是否要加入這個模塊到返回值中。on_error表示篩選出現(xiàn)異常時的處理,可以是:"raise"(拋出異常并停止pyinstaller構(gòu)建),"warn"(只拋出警告,不停止pyinstaller構(gòu)建),"warn once"(只警告一次,后續(xù)與之相同的警告被忽略),"ignore"(忽略,不拋出任何警告或異常)

例如:

# 收集Sphinx的所有子模塊(名字中不包含test)
hiddenimports = collect_submodules(
    "Sphinx", filter=lambda name: 'test' not in name)

collect_data_files(package, include_py_files=False, subdir=None, excludes=None, includes=None) 

返回一個模塊使用的所有非二進制文件。include_py_files表示返回的文件列表中是否應該含有*.py格式的文件。subdir是相對于要搜索的包的子目錄。excludes, includes分別是需要被排除和被包含的文件列表,可以指定它們來判斷是否要保留或移除某些格式的文件。

collect_dynamic_libs(package, destdir=None, search_patterns=['*.dll', '*.dylib', 'lib*.so'])

返回一個模塊使用的所有二進制動態(tài)庫文件。

collect_all(package_name, include_py_files=True, filter_submodules=None, exclude_datas=None, include_datas=None, on_error='warn once')

相當于上面的collect前綴的幾個函數(shù)的綜合。例如:

datas, binaries, hiddenimports = collect_all('my_module_name')

使用hooks模塊可以更加方便地制作鉤子。

6.3 為自己的模塊提供鉤子

如果自己創(chuàng)建的模塊需要鉤子,那么可以自己定義一個文件,并儲存到自己的模塊中。

如果你有一個名為module_name的模塊文件夾,首先在自己模塊的setup.cfg中(與setuptools模塊相關(guān),可自行搜索)添加如下代碼(注意里面的module_name):

[options.entry_points]
pyinstaller40 =
  hook-dirs = module_name.__pyinstaller:get_hook_dirs
  tests     = module_name.__pyinstaller:get_PyInstaller_tests

然后在module_name中添加名字為__pyinstaller的文件夾(與上面hook-dirs和tests里面的命名相一致即可)。

最后可以在__pyinstaller文件夾中添加hook文件。

7 常見問題

打包時報錯:不是可運行的命令或程序

首先檢查pyinstaller是否被成功安裝。在cmd輸入pip list,看安裝列表中是否存在pyinstaller,如果沒有則重新安裝,根據(jù)安裝信息進行處理。

如果顯示未找到pyinstaller,則應用絕對路徑指定pyinstaller。首先進入所在的文件夾,然后復制路徑。打包時,將pyinstaller替換為pyinstaller.exe的絕對路徑。(pyi-makespec找不到同理)

  • Windows: Python目錄下的Scripts文件夾
  • GNU/Linux: /usr/bin
  • macOS (using the default Apple-supplied Python) /usr/bin
  • macOS (using Python installed by homebrew) /usr/local/bin
  • macOS (using Python installed by macports) /opt/local/bin

例如,你想要執(zhí)行pyinstaller myscript.py,但是提示找不到pyinstaller.exe。在你的電腦上,pyinstaller.exe安裝在了C:\Python\Python310\Scripts這個位置,那么執(zhí)行:

C:\Python\Python310\Scripts\pyinstaller.exe myscript.py

還有一種解決方法,將pyinstaller.exe所在的文件夾添加到系統(tǒng)環(huán)境變量(推薦)。Windows上添加環(huán)境變量辦法如下:

右擊“此電腦” -> 單擊“屬性” -> 單擊“高級系統(tǒng)設置” -> 單擊“環(huán)境變量” -> 在用戶變量的位置單擊“Path” -> 單擊“編輯” -> 在“編輯環(huán)境變量”的窗口單擊“新建” -> 寫入pyinstaller.exe的所在路徑 -> 一路“確定”進行保存。

運行后報錯:找不到某些模塊或文件

找不到某些模塊,需要修改命令行參數(shù)--hidden-import,加入找不到的模塊。

如果提示找不到sys, os兩個模塊,那么命令行參數(shù)修改為:

pyinstaller --hidden-import "sys" --hidden-import "os" ...

如果使用Spec打包,則應在Analysis類的hiddenimport參數(shù)的列表中添加找不到的模塊。

如果只是找不到某些模塊中的部分文件,則需要為該模塊添加鉤子,或者將這些文件傳遞到命令行參數(shù)--add-data, --add-binary中。

運行后報錯:失去標準輸入

RuntimeError: input(): lost sys.stdin

某些程序打包后出現(xiàn)以上報錯內(nèi)容。這是由于代碼中使用了input這樣的函數(shù)讓用戶進行輸入,但是打包時卻設置了隱藏控制臺。于是,運行打包后的應用后就沒有一個控制臺讓用戶進行輸入,就會報錯。(失去stdout并不會報錯,但是print內(nèi)容不會顯示)

由于文檔內(nèi)容較多,很難涵蓋每一個點,如果你認為還有本文沒有提及的重點,請指出,歡迎任何建議者。

總結(jié)

到此這篇關(guān)于Python pyinstaller打包exe最新完整圖文教程的文章就介紹到這了,更多相關(guān)Python pyinstaller打包exe內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python+Flask實現(xiàn)自定義分頁的示例代碼

    Python+Flask實現(xiàn)自定義分頁的示例代碼

    分頁操作在web開發(fā)中幾乎是必不可少的,而flask不像django自帶封裝好的分頁操作。所以本文將自定義實現(xiàn)分頁效果,需要的可以參考一下
    2022-09-09
  • 利用OpenCV給彩色圖像添加椒鹽噪聲的方法

    利用OpenCV給彩色圖像添加椒鹽噪聲的方法

    椒鹽噪聲是數(shù)字圖像中的常見噪聲,一般是圖像傳感器、傳輸信道及解碼處理等產(chǎn)生的黑白相間的亮暗點噪聲,椒鹽噪聲常由圖像切割產(chǎn)生,這篇文章主要給大家介紹了關(guān)于利用OpenCV給彩色圖像添加椒鹽噪聲的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • 詳解Python 中的短路評估

    詳解Python 中的短路評估

    短路是指當表達式的真值已經(jīng)確定時終止布爾運算,Python 解釋器以從左到右的方式計算表達式,這篇文章主要介紹了Python 中的短路評估,需要的朋友可以參考下
    2023-06-06
  • python中random隨機函數(shù)詳解

    python中random隨機函數(shù)詳解

    大家好,本篇文章主要講的是python中random隨機函數(shù)詳解,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • Python MySQL數(shù)據(jù)庫基本操作及項目示例詳解

    Python MySQL數(shù)據(jù)庫基本操作及項目示例詳解

    這篇文章主要介紹了Python連接MySQL數(shù)據(jù)庫后的一些基本操作,并以銀行管理系統(tǒng)項目為例,為大家具體介紹了一下部分功能的實現(xiàn),文中的示例代碼具有一定的學習價值,感興趣的可以了解一下
    2021-12-12
  • Python?Pyinstaller庫安裝步驟以及使用方法

    Python?Pyinstaller庫安裝步驟以及使用方法

    pyinstaller是一個非常簡單的打包python的py文件的庫,下面這篇文章主要給大家介紹了關(guān)于Python?Pyinstaller庫安裝步驟以及使用方法的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • 使用Python實現(xiàn)U盤數(shù)據(jù)自動拷貝

    使用Python實現(xiàn)U盤數(shù)據(jù)自動拷貝

    這篇文章主要為大家詳細介紹了如何使用Python實現(xiàn)U盤數(shù)據(jù)自動拷貝,即當電腦上有U盤插入時自動復制U盤內(nèi)的所有內(nèi)容,希望對大家有所幫助
    2025-02-02
  • 解決python使用pd.read_csv()出現(xiàn)錯誤UnicodeDecodeError:?'utf-8'?codec?can't?decode......

    解決python使用pd.read_csv()出現(xiàn)錯誤UnicodeDecodeError:?'utf-8&

    你是否有過之前用pd.read打開csv文件都正常,但突然有一天運行以前的代碼就突然報錯,這篇文章主要給大家介紹了關(guān)于如何解決python使用pd.read_csv()出現(xiàn)錯誤UnicodeDecodeError:?'utf-8'?codec?can't?decode......的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • keras 多任務多l(xiāng)oss實例

    keras 多任務多l(xiāng)oss實例

    這篇文章主要介紹了keras 多任務多l(xiāng)oss實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • Python自動化測試框架pytest的詳解安裝與運行

    Python自動化測試框架pytest的詳解安裝與運行

    這篇文章主要為大家介紹了Python自動化測試框架pytest的簡介以及安裝與運行,有需要的朋友可以借鑒參考下希望能夠有所幫助,祝大家多多進步
    2021-10-10

最新評論