Python 打包与执行揭秘

Python 已成为世界上最广泛使用的编程语言之一。它驱动着从自动化脚本到大规模网络服务以及前沿机器学习的各种应用。

乍一看,Python 感觉很简单:

python myscript.py

这个单一的命令看似简单,但在背后,Python 正在执行多个复杂的步骤。当你想与他人分享你的 Python 项目时,你不仅仅是复制粘贴你的脚本——你依赖于一个复杂的打包生态系统,使软件能够在任何地方便携和可安装。

本文将指导您了解 Python 如何执行您的代码 以及 Python 应用程序是如何打包和分发的


1. Python 执行模型

当您运行一个 Python 程序时,您并不是直接执行 .py 文件。相反,Python 会经过一系列阶段。

  • 编写代码
    一切都始于您的源文件,通常以 .py 结尾。这是用 Python 语法编写的人类可读文本。

 

  • 编译为字节码
    在代码可以运行之前,Python 会将其编译成一种称为 字节码 的中间形式。这个字节码不是机器代码,而是一组更低级的指令,便于解释器执行。Python 将其存储在 .pyc 文件中,位于 __pycache__ 文件夹内以供重用,因此同一脚本的后续运行可以跳过此编译步骤。

 

  • 在 Python 虚拟机 (PVM) 中执行字节码随后被交给 Python 虚拟机 (PVM),它逐行执行这些字节码。PVM 是 Python 的核心引擎——它使您的代码能够在任何安装了 Python 的系统上运行。

与Java等语言不同,Python最常见的实现(CPython)不使用即时编译(JIT)。这意味着与编译语言相比,执行速度通常较慢,但这种权衡带来了灵活性和可移植性。

示例:当你运行python hello.py时,Python首先将其编译成字节码,然后PVM逐步读取并执行该字节码,直到你的程序完成。


2. 字节码与Python虚拟机(PVM)

字节码视为源代码与硬件之间的中间层。它不依赖于任何特定的机器或操作系统,这就是为什么同一个.py文件可以在Windows、macOS或Linux上运行而无需修改。

PVM是理解这些字节码的解释器。它的工作是在运行时将指令翻译成实际的机器操作。由于PVM是动态进行这一过程的,因此Python的速度比直接编译为机器代码的语言要慢,但它获得了巨大的可移植性

做一个类比:

  • 编写Python代码就像写食谱。
  • 字节码就像将该食谱翻译成一套通用的烹饪步骤。
  • PVM 就像是厨房里的厨师,负责阅读步骤并在你的厨房中烹饪美食。

无论你在哪个厨房(Windows、macOS、Linux),厨师(PVM)都可以制作相同的菜肴,只要字节码存在。


3. 为什么打包很重要

运行你自己的脚本是一回事。但如果你想与他人分享你的 Python 项目呢?你可以将 .py 文件发送给他们,但这会带来几个问题:

  • 不同的机器可能安装了不同版本的 Python。
  • 你的代码可能依赖于外部库,而其他人需要手动安装这些库。
  • 某些包包含编译组件,除非在目标系统上正确构建,否则无法正常工作。

这就是打包存在的原因。打包确保你的 Python 代码、依赖项和元数据以一致的方式捆绑在一起,以便任何人都可以可靠地安装它。

Python 主要使用两种分发格式:

  • 源代码分发 (.tar.gz)该格式包含你的原始源代码。当有人安装它时,他们的系统需要在本地构建,这意味着在安装时编译和解析依赖项。如果他们的环境没有正确设置,安装可能会失败。
  • 构建分发(.whl,Wheel 文件)Wheel 是一个预构建的包。它已经被编译并以 Python 所需的确切格式进行结构化。从 wheel 安装不需要构建——本质上只是提取文件。这使得安装速度更快,可靠性更高。

💡 类比:

源分发就像分享一个食谱以及所有的原料——你仍然需要自己烹饪。

而 wheel 就像收到一顿现成的饭菜:你只需 unpack 并享用即可。


4. Wheels(.whl)详解

wheel 格式 是为了解决安装需要编译的 Python 包时遇到的痛点而引入的。它在 PEP 427 中定义,已成为分发 Python 软件的标准格式。

为什么 wheels 很重要

  • 速度: 安装一个 wheel 只是解压和复制文件。不需要编译。
  • 稳定性: Wheels 避免了因缺少编译器或系统库而导致的安装失败。
  • 跨平台兼容性: 开发者可以发布针对特定平台的 wheel,确保它们在这些系统上“即插即用”。
  • 被 pip 优先选择: 像 pip 这样的工具在尝试从源代码构建之前,总是会优先尝试安装 wheel。

wheel 文件内部包含什么?

虽然 wheel 文件看起来像一个单一的 .whl 文件,但它实际上是一个 ZIP 压缩包,其中包含:

  • 编译后的或纯 Python 包代码。
  • 一个包含格式信息的 WHEEL 文件。
  • 一个 METADATA 文件,描述包的名称、版本、作者和依赖关系。
  • 一个 RECORD 文件,列出所有内容及其校验和。

这种结构确保了一致性,并使得 pip 安装变得简单。

理解 wheel 文件名

考虑这个例子:

numpy-1.26.4-cp311-cp311-win_amd64.whl

分解如下:

  • numpy → 包名称。
  • 1.26.4 → 版本号。
  • cp311 → 与 CPython 3.11 兼容。
  • win_amd64 → 为 Windows 64 位构建。

通过这种命名方案,pip 可以自动确定一个 wheel 是否与您的系统兼容。


5. pip 如何使用 Wheels

当您输入:

pip install numpy

pip遵循一个明确的流程:

  • 它查询Python包索引(PyPI)以获取可用版本。
  • 它查找与您的Python版本和平台匹配的wheel(.whl)。
  • 如果找到匹配项,它会立即下载并安装该wheel。
  • 如果没有可用的wheel,它会回退到源分发(.tar.gz),这需要在本地构建。

这种回退机制是导致某些安装速度极快而其他安装感觉极慢的原因。如果您曾经看过TensorFlow编译30分钟,那是因为pip无法找到适合您环境的wheel。

wheel的普及使得这种痛苦的安装变得不那么常见。如今,大多数主要库都会为多个平台发布wheel,从而确保顺畅的安装体验。


6. 结论

运行Python代码看似微不足道,但在表面之下却隐藏着一个强大且结构良好的系统:

  • Python将您的代码编译成字节码,然后通过PVM执行它。
  • 打包确保您的代码可以在任何地方共享和安装。
  • 源分发提供灵活性,但轮子已成为现代速度和可靠性的标准。
  • pip这样的工具通过优先使用轮子,使整个安装过程无缝进行,仅在必要时回退到源。

通过理解执行和打包的工作原理,您将能够调试棘手的安装错误,打包自己的库,并欣赏使Python开发如此高效的基础设施。

🚀 下次您运行pip install时,请记住:您不仅仅是在获取一些文件——您正在受益于多年的努力,使Python变得快速、可移植且对开发者友好。

更多