分发包 vs 导入包¶
“包”这个词通常指代许多不同的概念。本页面阐明了 Python 打包中两个不同但相关的含义:“分发包”和“导入包”之间的区别。
什么是分发包?¶
分发包是一个可以安装的软件。大多数情况下,这与“项目”是同义词。当你输入 pip install pkg,或者当你在 pyproject.toml 中写入 dependencies = ["pkg"] 时,pkg 是分发包的名称。当你搜索或浏览 PyPI(最广为人知的用于安装 Python 库和工具的集中式来源)时,你看到的是分发包列表。或者,“分发包”一词也可以指代包含项目某个特定版本的文件。
请注意,在 Linux 世界中,“分发包”(最常见的缩写是“distro package”或简称为“package”)是由 Linux 发行版的系统包管理器提供的东西,这是一个不同的含义。
什么是导入包?¶
导入包是一个 Python 模块。因此,当你在 Python 代码中写入 import pkg 或 from pkg import func 时,pkg 是一个导入包的名称。更准确地说,导入包是特殊的 Python 模块,可以包含子模块。例如,numpy 包包含 numpy.linalg 和 numpy.fft 等模块。通常,导入包是文件系统上的一个目录,其中包含作为 .py 文件的模块和作为子目录的子包。
一旦安装了提供导入包的分发包,你就可以使用它了。
分发包和导入包之间有什么联系?¶
大多数情况下,一个分发包提供一个单一的导入包(或非包模块),名称匹配。例如,pip install numpy 让你能够 import numpy。
然而,这只是一种约定。PyPI 和其他包索引**不强制**分发包的名称与它提供的导入包之间存在任何关系。(其结果是,如果你看到 import foo,你不能盲目地安装 PyPI 包 foo;这可能会安装一个非预期的,甚至可能是恶意的包。)
一个分发包可以提供一个不同名称的导入包。一个例子是流行的图像处理库 Pillow。它的分发包名称是 Pillow,但它提供导入包 PIL。这是出于历史原因:Pillow 最初是 PIL 库的一个分支,因此它保留了导入名称 PIL,以便现有 PIL 用户可以轻松切换到 Pillow。更普遍地说,现有库的分支是分发包和导入包名称不同的常见原因。
在给定的包索引(如 PyPI)上,分发包名称必须是唯一的。另一方面,导入包没有这样的要求。具有相同名称的导入包可以由多个分发包提供。同样,分支是造成这种情况的常见原因。
反之,一个分发包可以提供多个导入包,尽管这种情况不太常见。一个例子是 attrs 分发包,它既提供了具有较新 API 的 attrs 导入包,又提供了具有较旧但受支持 API 的 attr 导入包。
分发包名称和导入包名称如何比较?¶
导入包的名称应为有效的 Python 标识符(确切规则可在 Python 文档中找到)[1]。特别是,它们使用下划线 _ 作为单词分隔符,并且它们是区分大小写的。
另一方面,分发包可以使用连字符 - 或下划线 _。它们还可以包含点 .,有时用于打包 命名空间包 的子包。在大多数情况下,它们不区分大小写和 - 与 _ 的差异,例如,pip install Awesome_Package 与 pip install awesome-package 相同(具体规则在名称规范化规范中给出)。