本篇文章给大家谈谈python打包成一个可执行文件,以及python如何打包成可执行程序,希望对各位有所帮助,不要忘了收藏本站喔。
Source code download: 本文相关源码
2019年Python生态系统中比较流行的主题之一是关于打包和分发的。随着这一年的结束,我想总结一下我们目前可用来分发用Python构建的应用程序的多种途径怎样用python画弧形花瓣。虽然其中一些也适用于任何语言。
无论你交付的是可执行文件、虚拟环境、打包的代码还是完整的应用程序,下面的列表都包括了标准系统和一些在进入2020年时需要记住的新事物。
应用程序
要发布一个应用程序,你需要的不仅仅是一个从PyPI进行pip-install的库。你需要一种万无一失的在所有支持的操作系统中安装它及其依赖项的方式。这些依赖项可以包括其他非Python包以及像二进制文件或映像之类的外部资源。
下面是一些帮助你跨平台安装和分发代码的选项。
Docker
Docker使用操作系统中的基本功能来隔离进程,使其不知道系统的其余部分。它可以在你的主机内运行不同操作系统的内核进程,非常类似于虚拟化,但不使用虚拟硬件。
它的文件系统是分层的,因此占用的空间很小,只包含运行所需的文件,而不是典型的虚拟磁盘,虚拟机中还包括空闲空间。
使用一个最小程度打包的根文件系统,我们会看到整个操作系统的映像只占用几十MB,而不是虚拟机所需的GB,这并不少见。
你可以在一个公共注册中心(如DockerHub)或你的组织内部的一个私有注册中心分发这些容器。用户会在自己的计算机上安装Docker守护进程,然后使用它来获取你的映像并在本地运行它。
由于Docker映像只不过是一个根文件系统,所以你也可以将它们作为一个文件分发,并使用Docker导入它。
要构建一个映像,你可以从一个rootfs开始,或者在一个现有的注册表映像的基础上进行添加。大多数操作系统供应商在DockerHub中都维护了官方的精简映像,这些映像通常都很小。
其他组织也为他们的应用程序的新版本制作了官方映像,比如构建在Debian之上的Python映像。Postgress、MySQL、Redis、Nginx和许多其他标准服务也都是这样做的。
Docker现在可以在Linux、OSX和Windows上运行。这种跨平台支持意味着你构建的任何映像都具有广泛的分布,并且复杂性最小。你不仅可以控制应用程序,还可以控制它所运行的环境,从而使兼容性问题变得不那么严重。
然而,在配置网络或持续性存储时仍然可能存在复杂性。典型的应用程序只需要处理端口转发,但是有时候我们很难想象抽象层是如何工作的,所以编写良好的文档依然很重要。
使用Docker,你可以控制Python发行版、支持的OS包(如各个模块所需的C库)和你的虚拟环境。
由于启动一个容器只需要几毫秒的时间,所以每次当你想要执行应用程序时运行一个新的容器是完全可以接受的,甚至是推荐的。
有些人甚至使用Docker作为虚拟环境的替代品。由于它启动很快,并且可以提供一个交互式shell,所以当你需要处理一个特定的项目时,创建一个新容器并不是一个坏主意。
一旦你有了一个配置了基础环境的运行容器,你就可以保存该映像以便重用,或者甚至可以将其导出到文件中。
例如,下面的命令会启动一个新的Python容器,将当前工作目录挂载为/work,并将你放入一个bash shell中。容器目录中的更改反映在基础目录中。
一旦进入容器,你就可以安装任何需要的Apt或PyPI包。
退出shell后你将会返回到主机。此时,你可以运行下一条命令将任何的更改保存为一个新的Docker映像,你可以稍后重用它或将其推送到DockerHub进行分发:
你可以在你组织内部的私有Docker 注册表中共享此新映像,或者运行以下命令将该容器导出为一个文件,任何人都可以下载它并将其导入他们的本地Docker环境中:
然而,分发的真正工作流程是创建一个Dockerfile,任何人都可以使用它来创建自己的映像。换句话说,你提供了一个带有Docker守护进程指令的小型文本文件,而不是整个文件系统的副本。
任何人都可以使用该文件克隆你的repo,并运行此命令去创建一个此映像的本地版本:
一个典型的Dockerfile如下所示,请查看他们的文档以获取更多信息:
更过详情:https://docs.docker.com/
虚拟机和Vagrant
容器的下一步是分发一个完整的虚拟机。自从虚拟化得到广泛应用和硬件支持以来,这种类型的系统已经存在了一段时间了。
交付一个“虚拟设备”是很有吸引力的,因为你几乎可以完全控制你的应用程序运行的环境。所有东西都是可配置的:操作系统、它的包、磁盘和网络,甚至空闲空间的大小。
使用虚拟机的缺点是发行版的大小,通常是在GB级。另外,你还得想办法让客户得到你的映像。Amazon S3 或 Digital Ocean Spaces之类的东西就是一个很好的起点。
一开始,只有服务器硬件支持运行虚拟机,但是现在每个处理器都有这个能力,而且所有主要的操作系统都支持它。还有一些免费的应用程序可以帮助你管理和配置虚拟机,比如Oracle的VirtualBox。
Vagrant是在VirtualBox等管理器上配置和运行虚拟机的另一个系统。它的功能很像Docker,你可以在一个文件中指定虚拟机所需要的所有东西,它可以为你构建和运行该虚拟机。
与前一节中的Dockerfile类似,Hashicorp的Vagrant使用一个Vagrantfile,其中包含有关如何启动和配置虚拟机的指令。
就像Docker映像提供了运行容器的基本文件系统一样,Vagrant box也为虚拟机提供了基础文件系统。
下面的示例Vagrantfile与上一节中的Dockerfile所做的事情类似:
使用这个文件克隆你的存储库,并运行这些命令来启动VM,然后你就会进入它的shell:
Vagrant确实通过使用Vagrant Box catalog提供与DockerHub类似的体验来帮助我们解决分发问题。
有了它,你可以得到你的基础映像或上传新的映像与他人分享。你甚至可以将一个Vagrantfile指向内部的URL去下载一个box。
更多详情:https://www.vagrantup.com/intro/index.html
PyInstaller
我们之前已经介绍过这个模块。PyInstaller负责绑定运行你的应用程序所需的所有资源,包括Python发行版。在爬取你的代码时,它会指出要打包哪些Python依赖项,同时仍然允许你指定其它要包括在bundle中的资源。
它的打包结果是一个适用于Windows、Linux或OSX的可安装应用程序。在执行期间,它会将该程序与绑定的解释器一起解压到一个文件夹中,并运行你的入口点脚本。
它足够灵活,可以让你控制Python发行版和执行环境。我甚至成功地使用它将浏览器与我的Python包绑定在一起。
但使用它确实会带来麻烦。在提取自身时,它将更改应用程序运行的基本目录。这意味着,任何依赖__file__来确定当前执行路径的代码现在都需要使用PyInstaller配置的内部环境。
分发你的bundle完全取决于你。对于这种类型的设置,大多数人选择对象存储和CDN。
在以这种方式分发时要记住一点,即检查你的代码是否需要验证它所运行的操作系统环境。
换句话说,与使用Docker或Vagrant不同,如果你需要安装特定的apt包,那你就无法保证该包在执行期间就已经存在。
更多详情:https://www.pyinstaller.org/
Briefcase
Briefcase是这类产品的后起之秀。它是Beeware项目的一部分,该项目旨在将Python应用程序打包分发给所有操作系统和设备,包括Android和iOS。
它与PyInstaller处于类似的领域,这意味着它可以将你的模块及其依赖项绑定到一个可安装的应用程序中。但它也增加了对移动设备和带有AppleTV或tvOS的电视的支持。
不幸的是,其文档仍然有点松散,而且主要是以示例的形式。然而,该项目很有前景,并且仍在积极开发中。颇受欢迎的编辑器Mu就将它用于打包。
你可以将使用Briefcase构建的应用程序提交到Android和Apple应用商店进行分发。
更多详情:https://beeware.org/project/projects/tools/briefcase/
虚拟环境
有时,我们可以假设你的用户拥有一个标准的操作系统。也许他们都是从公司内部的IT部门构建的库存映像运行的。也许你的应用程序很简单,根本不必担心操作系统或解释器的复杂性。
如果你只需要考虑Python代码及其依赖关库,那么这个类别适合你。
Pex
Pex是由Twitter的员工构建的,它是一种将整个虚拟环境与你的Python应用程序一起发布的方法。它被设计为使用一个预先安装的Python解释器,它利用了为Python Zip应用程序构建的标准(在PEP-441中有概述)。
从Python 2.6开始,解释器就能够将目录或zip格式的归档文件作为脚本执行。
Pex构建在此基础之上,简化了复制单个文件的分发过程。这些文件可以在不同的平台(OSX、Linux、Windows)以及不同的解释器上工作。尽管在使用带有C绑定的模块时存在一些限制。
在你的基本系统中安装Pex之后,你可以使用它生成一个包含整个Python环境的文件。
将该文件传递到你同事的计算机,你将能够在那里执行该文件,而不需要安装除基本Python解释器之外的任何东西。
你甚至可以在解释器模式下运行一个文件,这样它就会打开一个Python REPL,其中包含你的环境中可以导入的所有必要模块。
将你的虚拟环境冻结为一个.pex文件相当简单:
然后你可以执行该文件来打开一个带有你的环境的REPL:
你还可以在创建文件时指定入口点,以便它可以在你的模块中执行特定的函数,就像你直接运行python命令一样。
目前没有系统可以为你分发Pex文件,因此,就像前面的项目一样,你只能使用公共对象存储和CDNs。
更多详情:https://github.com/pantsbuild/pex
Shiv
与Pex类似,LinkedIn的人员建立了一个不同的模块,称为Shiv。他们构建一些不同的东西的主要原因是试图在Pex可执行文件的开始期间尝试并解决一个问题。考虑到存储库和依赖项的复杂性,他们希望以不同的方式处理环境设置。
代替将各种轮子与应用程序一起打包,Shiv会包含一个完整的由pip安装的site-packages目录。这让所有的东西都能开箱即用,并且速度几乎是Pex的两倍。
这里是一个如何使用Shiv生成一个.pyz文件的例子,它做了一些与Pex部分类似的事情:
然后,你就可以使用以下命令直接执行它:
需要注意的是,打包带有OS依赖项的库在平台之间是不交叉兼容的。正如在Pex部分中提到的,这主要是依赖于底层C库的模块的问题。你必须为每个平台生成不同的文件。
同样,目前还没有让你分发这些文件的构建系统,所以你必须依赖AWS、DO、CDNs或其他应用商店,如JFrog的Artifactory或Sonatype的Nexus。
更多详情:https://github.com/linkedin/shiv
Pipx
虽然不是构建应用程序或分发它们的方法,但Pipx提供了一种不同的方式来安装它们。它与你的操作系统一起工作,以隔离虚拟环境及其依赖项,更接近于Homebrew等系统对OSX的作用。
Pipx提供了一种简单的方法,可以让你将包安装到隔离的环境中,并全局地公开它们的命令行入口点。它还提供了一种机制来列出、升级和卸载这些包,而不涉及虚拟环境的细节。
一个很好的例子就是linter的使用。假设你在多个python应用程序上工作,每个应用程序都有一个单独的virtualenv,你希望使用flake8在所有应用程序上执行相同的linting操作。
代替将flake8模块安装到每个virtualenv中,你可以使用Pipx来安装一个全系统范围的flake8命令,该命令在每个环境中都可用,但运行在它们自己完全独立的环境中。
更多详情:https://pypi.org/project/pipx/
单文件可执行文件
有时,你希望为客户提供一个不需要预装库即可运行的可执行文件,就像你使用Docker或Pex一样。
这里描述的机制可以帮助你完成此任务。和前面的类别一样,它们都需要某种形式的对象或应用商店来帮助分发。
PyInstaller
虽然我们已经讨论了PyInstaller,但是在这个类别中还是值得再次提及它,因为这是它的主要功能之一。
它可以生成整个应用程序的单个可执行文件,并绑定所有依赖项。你可以为每个操作系统创建一个,它就可以像任何其他本机应用程序一样运行。
PyOxidizer
作为打包和分发领域的最新产品之一,PyOxidizer非常有前途。它利用了为Rust编程语言创建的打包工具。
与PyInstaller非常相似,你可以完全控制想要绑定到其中的所有内容,但它也可以允许你执行类似Pex或Shiv的代码。这意味着你可以创建你的包,使它作为一个REPL运行,其中的所有依赖项都已预先安装。
分发一个包括REPL的完整Python环境会产生一些令人兴奋的应用程序,特别是对于需要多个包来进行数据探索的研究团队或科学计算。
与PyInstaller相比的一个优点是,它不是提取到文件系统,而是将自身提取到内存中,从而大大缩短了实际的Python应用程序的启动时间。
这个特性与PyInstaller有类似的缺点。你必须将任何内部引用调整为__file__或类似的操作,因此它们依赖于运行时PyOxidizer配置的环境。
更多的细节可以在他们的官方文档中找到,但我们也在这篇文章中对此做了很多的介绍。
Nuitka
除了使用一个绑定的解释器执行Python代码之外,你还可以选择将代码编译为C。这带来了几个好处,包括更快执行的可能性,因为C编译器可以执行解释器无法执行的优化。
Nuitka是为将Python代码编译成C而构建的系统。虽然这个概念类似于更广为人知的Cython,但它不是一种单独的语言。它还能做Cython做不到的事情,比如抓取依赖项并将所有东西编译成一个二进制文件。
生成的可执行文件能在本地代码中以更快的速度运行,并且不需要提取。
编译可能会变得很复杂,尤其是考虑到平台的复杂性时。但是如果你为它安排好了时间,你就能获得好处。我以前成功地做过几次。
更多详情:https://nuitka.net/
应用商店体验
我们几乎每天都在使用的其他应用程序分发系统:应用商店。此软件用于安装和维护其他应用程序。
就像Apple App Store或谷歌Play Store一样,在Linux中也有类似的机制来支持简单的集成。
Snapcraft
Snapcraft提供标准的应用商店体验。你可以将你的应用程序发布到他们的商店,用户可以在那里发现并安装它。
安装是独立的,以避免与其他应用程序发生冲突,并且它可以跨Linux发行版工作,包括库依赖项。
安装后,应用商店会自动将应用程序保持在最新的稳定版本,并提供一种机制来在保留数据同时恢复到以前的状态。
Ubuntu管理着这个商店,所以你在打包了你的应用程序(或者他们所说的snap)之后,你必须用一个注册的Ubuntu One帐号将这个snap发布到商店。
更多详情:https://snapcraft.io/
Flatpak
另一个与Snapcraft非常相似的概念是Flatpak。
它还通过使用容器技术为应用程序提供隔离来提供与FlatHub.org类似的存储体验。不过,您也可以托管自己的私有hub,或者在单个文件中分发包。
Flatpak包还可以利用一些桌面集成功能。它们提供了诸如位置检测、访问应用程序外部资源的能力(很像您的手机请求权限去打开文件或URL)、通知、窗口装饰等信息。
更多创建您的第一个Flatpak的细节和说明,请查看这里:http://docs.flatpak.org/en/latest/first-build.html#
总结
我们拥有一个完整的、功能丰富的应用程序打包和分发机制生态系统。其中大多数都不是特定于Python语言的,但是很容易与它进行集成。
虽然分发应用程序看起来有很多选择,但我希望这里应用的分类能帮助您根据你可以控制的部分选择最适合您需要的方式。
英文原文:https://tryexceptpass.org/article/distributing-python-applications/
译者:Nothing