1. 程式人生 > 實用技巧 >part17:Python打包和釋出(zipapp,PyInstaller)

part17:Python打包和釋出(zipapp,PyInstaller)


知識點:

  • 釋出 Python 程式
  • 使用 zipapp 生成可執行的 Python 檔案包
  • 使用 zipapp 建立獨立應用
  • 安裝 PyInstaller 模組
  • 使用 PyInstaller 生成 EXE 程式

經過一系列的開發、除錯後得到的 Python 程式,接下來就是將這個程式釋出出來。

兩個常用的釋出工具:zipapp 和 PyInstaller。

zipapp 模組生成可執行的 Python 檔案包,該檔案包包含目錄下所有的 Python 程式。如果使用 pip 工具先將 Python 程式所依賴的模組下載到目錄下,那麼就可以生成可獨立遠行的 Python 程式,只要目示機器上安裝有 Python 直譯器環境即可。

PyInstaller 工具更強大,可以直接將 Python 程式編譯成 Windows、Mac OS X 平臺上的可執行程式,而無須這些機器上安裝 Python 環境。


一、使用 zipapp 模組

zipapp 模組可以將一個 Python 模組(可能包含很多個源程式)打包生成一個 Python 應用,或者釋出成一個 Windows 的可執行程式。


1、生成可執行的 Python 檔案包

zipapp 是一個可以直接執行的模組,該模組用於將單個 Python 檔案或整個目錄下的所有檔案打包成可執行的檔案包。命令列語法如下:

python -m zipapp source [options]

source 引數是要打包的 Python 源程式或目錄。如果source引數是目錄,則 zipapp 模組會打包該資料夾中的所有 Python 檔案。options 引數提供的選項如下:

  • -o <output>, --output=<output>:指定輸出檔案包的檔名,如果不指定,則使用預設檔名,預設是 source 引數值加上 .pyz 字尾。
  • -p<interpreter>, --python=<interpreter>:指定 Python 直譯器
  • -m <mainfn>, --main=<mainfn>:指定入口函式。該選項為 pkg.mod:fn 形式,其中 pkg.mod 是一個檔案包中的包或模組,fn 是指定模組中的函式。如果不指定該選項,則預設從模組中的 __main__.py
    檔案開始執行。
  • -c, --compress:從 Python 3.7 開始支援該選項,指定檔案包進行壓縮來減小檔案的大小,預設是不壓縮。
  • --info:在診斷時顯示檔案包中的直譯器。
  • -h, --help:顯示 zipapp 模組的幫助資訊。

zipapp 使用示例:建立一個 app 子目錄,該子目錄下可以有多個 Python 原始檔,在該目錄下的第一個原始檔是 say_hello.py,程式碼如下:

def say_hello(name):
    return name + ",您好!"

第二個原始檔是:app.py,用來使用 say_hello 模組,程式碼如下:

from sys import argv
from say_hello import *

def main():
    print('開始執行程式')
    for arg in argv[1:]:
        print(say_hello(arg))

回到 app 子目錄的上一級目錄,在命令列下執行下面的命令:

python -m zipapp app -o first.pyz -m "app:main"

執行上面命令後,app 子目錄下的所有 Python 原始檔都會打包成一個檔案包,-o 選項指定的就是檔案包的檔名;-m 選項指定使用 app.py 模組中的 main 函式作為程式入口。此時在當前目錄會生成一個 first.pyz 檔案,可使用 Python 命令來執行該檔案。示例如下:

> python first.pyz michael tom
開始執行程式
michael,您好!
tom,您好!

在執行打包命令時,如果不指定 -o 引數,則預設輸出的檔名是 source 引數值加上 .pyz字尾組成,例如:

python -m zipapp app -m "app:main"

此時會在當前目錄下生成 app.pyz 檔案。


2、建立獨立應用

為了建立能夠獨立啟動的應用(自帶依賴模組和包),需要執行兩步操作:

第1步:將應用依賴的模組和包下載到應用目錄中。

第2步:使用 zipapp 將應用和依賴模組一起打包成檔案包。

使用 zipapp 建立獨立應用示例:建立 dbapp 子目錄作為本應用的目錄,該目錄下的第一個 Python 原始檔是 exec_select.py 檔案,該原始檔程式碼如下:

import mysql.connector

# 將執行程式碼封裝到 query_db 函式中
def query_db():
    # 第1步:連線 MySQL 資料庫,需要提供伺服器IP地址、資料庫埠號、資料庫使用者名稱和密碼,以及資料庫名稱
    conn = mysql.connector.connect(user='michael', password='michael123', host='192.168.64.50',
                                   port='3508', database='python', use_unicode=True)
    conn.autocommit = True
    # 第2步:獲取遊標
    c = conn.cursor()
    # 第3步:呼叫遊標的 execute() 方法執行 select 查詢語句
    c.execute('select * from user_tb where user_id > %s', (4,))
    # 通過遊標的 description 屬性獲取列欄位資訊
    for col in (c.description):
        print(col[0], end='\t')
    print('\n-------------------------------')
    # 直接使用 for 迴圈遍歷遊標中的結果集
    for row in c:
        print(row)
        print(row[1] + '-->' + row[2])

    # 第4步:關閉遊標
    c.close()
    # 第5步:關閉連線
    conn.close()

exec_select.py 檔案的程式碼主要是查詢 MySQL 資料庫中的資料,將主要的執行程式碼都封裝到 query_db() 函式中。

在 dbapp 目錄下的第二個 Python 原始檔是 __main__.py,這個檔案作為程式入口,這樣在打包檔案時就不需要指定程式入口。該檔案的程式碼如下:

from exec_select import *

# 執行 query_db() 函式
query_db()

接下來按照下面3步將 dbapp 子目錄下的應用打包成獨立應用:

第1步:通過命令列工具在 dbapp 所在的目錄執行下面命令:

python -m pip install -r requirements.txt --target dbapp

上面的命令就是在使用 pip 模組來安裝模組,平時使用 pip 安裝模組提示 pip 錯誤時,也可以使用 python -m pip install 來安裝模組。--target 選項是將模組安裝到指定目錄下,這裡指定的是 dbapp 子目錄下。-r 選項指定要安裝哪些模組,這裡使用 requirements.txt 檔案列出要安裝的模組和包。

-r 選項後面可以直接指定要安裝的模組和包,也可使用清單檔案指定要安裝的模組和包。

如果應用依賴的模組較多,建議使用清單檔案來列出所依賴的模組。為了執行上面的命令,需要提前在當前目錄下準備好 requirements.txt 檔案,該檔案中的內容就一行:

mysql-connector-python

這個 requirements.txt 檔案的每一行代表一個模組,如果有多個依賴模組,就在這個檔案中新增多個模組名的行。執行上面的命令,就開始安裝 mysql-connection-python 模組。完成後可以在 dbapp 子目錄下看到大量有關 mysql-connection-python 模組的檔案。

第2步:如果 pip 在 dbapp 子目錄下生成了 .dist-info 目錄,可以刪除該目錄。

第3步:使用 zipapp 模組執行打包操作,這次有了 __main__.py 檔案,該檔案會作為程式入口,因此在打包時不需要指定 -m 選項。打包命令如下:

python -m zipapp dbapp

此時會在當前目錄得到一個 dbapp.pyz 的檔案包,該檔案包約 20MB,因其包含了 myql-connector-python 模組。

現在,只要目標機器上有合適的 Python 直譯器,即可執行該獨立應用。可先將本機上的 myql-connector-python 解除安裝進行測試。解除安裝命令是:

pip uninstall myql-connector-python

二、使用 PyInstaller 生成可執行程式


1、安裝 PyInstaller

PyInstaller 模組需要自行安裝,安裝命令如下:

pip install pyinstaller

由於該模組還依賴其他模組,所以儘量不要採用離線包方式安裝。若成功安裝,可以在安裝介面看到類似下面的資訊:

Successfully installed pyinstaller-3.6

其中的 3.6 之類的數字,代表 PyInstaller 的版本號。此時,在Python 安裝目錄下的 Script 目錄下也會增加一個 pyinstaller.exe 程式。使用該工具可將 Python 程式生成 EXE 程式。


2、生成可執行程式

PyInstaller 工具的命令語法如下:

pyinstaller 選項 Python原始檔

不管這個 Python 應用是單檔案的應用,壓是多檔案的應用, 只要在使用 pyinstaller 命令時編譯作為程式入口的Python 程式即可。

為了進行示例,先將前面的 app.py 檔案略做修改,將該檔案改成可執行的 Python 程式。程式碼如下:

from sys import argv
from say_hello import *

def main():
    print('開始執行程式')
    if len(argv[1:]) >= 1:
        for arg in argv[1:]:
            print(say_hello(arg))
    else:
        print(say_hello('michael'))

# 增加呼叫 main() 函式
if __name__ == '__main__':
    main()

接下來使用命令列工具進入到 app 目錄下,在該目錄下執行下面命令:

pyinstaller -F app.py

執行上面命令,可以看到詳細的生成過程。生成完成後,在app目錄下有一個 dist 目錄,在該目錄下有一個 app.exe 檔案,這就是用 PyInstaller 工具生成的 EXE 程式。

在命令列視窗中進入到 dist 目錄,即可執行 app.exe 程式,示例如下:

...app\dist> .\app.exe tom jack
開始執行程式
tom,您好!
jack,您好!

需要注意的是,這個程式沒有圖形介面,如果雙擊 app.exe 來執行程式,會看到視窗一閃就消失,這樣也看不到程式輸出結果。

另外,pyinstaller 的 -F 選項是指定生成單獨的 EXE 檔案,生成的檔案在 dist 目錄下。在 Mac OS X 平臺上生成的檔案不帶 .exe 字尾。與 -F 選項對應的是 -D 選項(預設選項),該選項指定生成一個目錄(包含多個檔案)來作為程式。

下面使用 -D 選項進行示例。先將 PyInstaller 工具在 app 目錄下生成的 build、dist 目錄刪除,將 app.spec 檔案刪除。然後在app目錄使用下面命令生成 EXE 檔案:

pyinstaller -D app.py

執行這個命令,同樣可以看到詳細的生成過程。生成完成後,在當前目錄下多出一個 dist 目錄,在 dist 目錄下有一個 app 子目錄,在該子目錄下包含了大量的 .dll 檔案和 .pyz 檔案,這些都是 app.exe 程式的支撐檔案。在命令列視窗中執行 app.exe 程式,同樣可以正常輸出。

PyInstaller 不僅支援 -F、-D 選項,還支援其他選項,支援的常用選項如下表所示:

選項 作用
-h, --help 檢視該模組的幫助資訊
-F, --onefile 產生單個的可執行檔案
-D, --onedir 產生一個目錄(包含多個檔案)作為可執行程式
-a, --ascii 不包含 Unicode 字符集支援
-d, --debug 產生 debug 版本的可執行檔案
-w, --windowed, --noconsole 指定程式執行時不顯示命令列視窗(僅對 windows 有效)
-c, --nowindowed, --console 指定使用命令列視窗執行程式(僅對 windows 有效)
-o DIR, --out=DIR 指定 spec 檔案的生成目錄。如果沒有指定,則預設使用當前目錄來生成 spec 檔案
-p DIR, --path=DIR 設定 Python 匯入模組的路徑(和設定PYTHONPATH環境變數的作用相似),也可使用路徑分隔符(Windows用分號,Linux用冒號)來分隔多個路徑
-n NAME, --name=NAME 指定專案(產生的spec)名字。如果省略,那麼第一個指令碼的主檔名將作為 spec 的名字

PyInstaller 的選項不止上表這些,可以使用 -h 選項檢視 PyInstaller 選項的詳細資訊。

下面使用 PyInstaller 建立一個帶圖形使用者介面,可以訪問 MySQL 資料庫的應用程式。為此,新建一個 dbapp 目錄,將前面建立的 exec_select.py 檔案和 __main__.py 拷貝到新建的 dbapp 目錄,在該目錄下執行下面的命令:

pyinstaller -F -w __main__.py

上面命令中,-F 選項生成單個可執行檔案,-w 選項指定生成圖形使用者介面程式。現在在 dist 子目錄下找到 __main__.exe 檔案,雙擊該檔案即可執行該程式。


小結:

  • Python 的兩種打包工具:zipapp 和 PyInstaller。
  • zipapp 將檔案打包成一個 .pyz 檔案,該檔案需要 Python 環境來執行。
  • PyInstaller 直接打包成可執行程式,該工具還是跨平臺,使用也很方便。使用該工具打包的程式,可以分發到對應平臺的目標機器上直接執行,無須在目標機器上安裝 Python 直譯器環境。