part17:Python打包和发布(zipapp,PyInstaller)

时间:2024-03-07 18:36:41

知识点:

  • 发布 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 解释器环境。