Python作为一门编程语言对用它开发的项目的版本格式没有任何限制。实际上大多数的 Python 代码根本没有版本这个属性。在 PEP345 通过之前,项目版本的格式几乎是无关紧要的。然而这个 PEP345 给 Disutils 模块增加了一个 Requrie-Dist 属性,试图通过它和其他增改的属性来解决不同 Python 项目之间的依赖关系难以表述的问题。有了它,将来的项目可以通过原生的 Python 环境来提供自己的安装和卸载信息,包括对其他项目的依赖。这样 Python 就获得了类似 Debian Linux 下面 apt-get 工具的能力!"
这个 PEP 的通过对 Python 项目的使用者和开发者都是一个好消息。
那么这个 PEP 和版本号有什么关系呢?答案是新增的 Require-Dist 属性里可以包含版本范围的信息(x项目以来y项目的版本不小于z)。而这个信息自然会应用到版本大小的比较。如果一个项目的版本格式是随机的,那 Python 项目的安装工具就无法识别 Require-Dist 里的版本范围,从而无法通过比较版本大小来安装项目的依赖包。所以作为一个 Python 开发者,如果想让自己的项目能在将来顺利安装,最好还是从今天开始使用规范的版本系统和格式。
怎样的版本格式才算规范呢?Python 核心已经通过 PEP386 为我们回答了这个问题。Python 在将来能原生识别和比较的版本应该具有以下格式:
N.N[.N]+[{a|b|c|rc}N[.N]+][.postN][.devN]
从左向右做一个简单的解释:
"N.N": 版本号里唯一必备的部分,两个"N"分别代表了主版本和副版本号,绝大多数现存的工程里都包含该部分。
"[.N]": 次要版本号,可以有零或多个。
"{a|b|c|rc}": 阶段代号,a, b, c, rc分别代表alpha, beta, candidate 和 release candidate, 可选
"N[.N]": 阶段版本号,如果提供,则至少有一位主版本号,后面可以加无限多位的副版本号。
".postN": 发行后更新版本号,可选。
".devN": 开发期间的发行版本号,可选。
不难看出这个格式其实是建立在大多数既存项目已经普遍应用的格式的基础之上的,这也是这个PEP的提出者的初衷:尽量保持与现状的兼容性。
下面举几个规范版本格式的例子:
'1.2'
'3.2.3.2c5.4.12' (3.2.3.2 的 candidate 阶段的 5.4.12 版本)
'2.7.dev231' (2.7开发版231次发行)
'1.0.1rc2.post2' (1.0.1 的 release candidate 第二发行版本)
符合规范的版本号即使格式不同也能相互进行比较,PEP386 里面给的例子能说明很多问题:
>>> from verlib import NormalizedVersion as V
>>> (V('1.0a1')
... < V('1.0a2.dev456')
... < V('1.0a2')
... < V('1.0a2.1.dev456')
... < V('1.0a2.1')
... < V('1.0b1.dev456')
... < V('1.0b2')
... < V('1.0b2.post345')
... < V('1.0c1.dev456')
... < V('1.0c1')
... < V('1.0.dev456')
... < V('1.0')
... < V('1.0.post456.dev34')
... < V('1.0.post456'))
True
结果非常的符合直觉。至少 DaNmarner 是这么觉得。
最后补充: 上面例子中的 verlib 还在开发阶段,代码在这里,它将成为未来的 distutils.version 模块。 PEP 386 是 Python 和 Ubuntu,Fedora 一起提出的。
你的 Python 项目有一个符合 PEP386 的版本吗?