如何在Python比较的版本号?(How do I compare version numbers

2019-06-17 17:00发布

我正包含鸡蛋鸡蛋那些添加到目录中sys.path 。 如果在目录中的相同.egg的两个版本,我想只有最新一次加。

我有一个正则表达式r"^(?P<eggName>\w+)-(?P<eggVersion>[\d\.]+)-.+\.egg$ 。来提取文件名的名称和版本的问题是比较的版本号,这就好比一个字符串2.3.1

由于我比较字符串,2种以上的10,但是这是不正确的版本。

>>> "2.3.1" > "10.1.1"
True

我可以做一些分解,分析,铸造为int,等等,我最终会得到一个解决方法。 但是,这是Python的, 而不是Java 。 有一种优雅的方式来比较版本字符串?

Answer 1:

使用packaging.version.parse

>>> from packaging import version
>>> version.parse("2.3.1") < version.parse("10.1.2")
True
>>> version.parse("1.3.a4") < version.parse("10.1.2")
True
>>> isinstance(version.parse("1.3.a4"), version.Version)
True
>>> isinstance(version.parse("1.3.xy123"), version.LegacyVersion)
True
>>> version.Version("1.3.xy123")
Traceback (most recent call last):
...
packaging.version.InvalidVersion: Invalid version: '1.3.xy123'

packaging.version.parse是一个第三方工具,但使用setuptools的 (所以你可能已经安装)和是否符合特定当前PEP 440 ; 它会返回一个packaging.version.Version如果版本兼容和packaging.version.LegacyVersion如果不是。 后者将始终排序之前有效版本。


仍在使用的很多软件的一个古老的替代方案是distutils.version ,建于无证却符合性,并仅向替代PEP 386 ;

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
True
>>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
True
>>> StrictVersion("1.3.a4")
Traceback (most recent call last):
...
ValueError: invalid version number '1.3.a4'

正如你可以看到它认为有效的PEP 440个版本的“不严格”,因此不匹配的有效版本是什么现代Python的概念。

作为distutils.version是无证, 这里的相关文档字符串。



Answer 2:

setuptools的定义parse_version() 这实现PEP 0440 -版本识别 ,并且还能够解析不遵循PEP版本。 该功能使用easy_installpip来处理版本比较。 从文档 :

解析由PEP 440返回的值定义将是代表版本的对象项目的版本字符串。 这些对象可以被彼此比较和排序。 该排序算法是由PEP 440与另外的任何版本,这是不是一个有效的PEP 440版本将被认为比任何有效的PEP 440版和无效的版本不太会继续使用原来的算法排序定义。

“原始算法”引用在旧版本的文档的定义,之前PEP 440存在。

语义上,该格式是的distutils'之间的交叉粗糙StrictVersionLooseVersion类; 如果你给它,将一起工作的版本StrictVersion ,那么他们会比较相同的方式。 否则,比较更像是一个“聪明”的形式LooseVersion 。 它可以创建病理版本编码方案欺骗这种解析器,但他们应该在实践中非常罕见。

该文件提供了一些例子:

如果你想成为某些你所选择的编号方案运作的,你认为这会,您可以使用的方式pkg_resources.parse_version()函数来比较不同的版本号:

 >>> from pkg_resources import parse_version >>> parse_version('1.9.a.dev') == parse_version('1.9a0dev') True >>> parse_version('2.1-rc2') < parse_version('2.1') True >>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9') True 

如果你不使用setuptools的,该包装项目拆分成独立的库这和其他包装相关的功能。

from packaging import version
version.parse('1.0.3.dev')

from pkg_resources import parse_version
parse_version('1.0.3.dev')


Answer 3:

def versiontuple(v):
    return tuple(map(int, (v.split("."))))

>>> versiontuple("2.3.1") > versiontuple("10.1.1")
False


Answer 4:

出了什么问题转化版本字符串转换成一个元组,并从那里去? 看来优雅足以让我

>>> (2,3,1) < (10,1,1)
True
>>> (2,3,1) < (10,1,1,1)
True
>>> (2,3,1,10) < (10,1,1,1)
True
>>> (10,3,1,10) < (10,1,1,1)
False
>>> (10,3,1,10) < (10,4,1,1)
True

@ kindall的解决方案是的代码是多么的美好期待一个简单的例子。



Answer 5:

有包装封装,这将让您比较版本为每PEP-440 ,以及旧版本。

>>> from packaging.version import Version, LegacyVersion
>>> Version('1.1') < Version('1.2')
True
>>> Version('1.2.dev4+deadbeef') < Version('1.2')
True
>>> Version('1.2.8.5') <= Version('1.2')
False
>>> Version('1.2.8.5') <= Version('1.2.8.6')
True

旧版本的支持:

>>> LegacyVersion('1.2.8.5-5-gdeadbeef')
<LegacyVersion('1.2.8.5-5-gdeadbeef')>

比较PEP-440版本的旧版本。

>>> LegacyVersion('1.2.8.5-5-gdeadbeef') < Version('1.2.8.6')
True


Answer 6:

您可以使用semver包,以确定是否一个版本用于满足一个语义版本要求。 这是不一样的比较两个实际的版本,但它是一个类型的比较。

例如,版本3.6.0 + 1234应该是一样的3.6.0。

import semver
semver.match('3.6.0+1234', '==3.6.0')
# True

from packaging import version
version.parse('3.6.0+1234') == version.parse('3.6.0')
# False

from distutils.version import LooseVersion
LooseVersion('3.6.0+1234') == LooseVersion('3.6.0')
# False


Answer 7:

发布基于Kindall的解决方案我的全部功能。 我能够通过填充带前导零的每个版本部分支持与数字混合的任何字母数字字符。

虽然肯定不如漂亮,他的一行功能,它似乎与字母数字版本号很好地工作。 (只是一定要设置zfill(#)如果你在你的版本系统长串相应的值,。)

def versiontuple(v):
   filled = []
   for point in v.split("."):
      filled.append(point.zfill(8))
   return tuple(filled)

>>> versiontuple("10a.4.5.23-alpha") > versiontuple("2a.4.5.23-alpha")
True


>>> "10a.4.5.23-alpha" > "2a.4.5.23-alpha"
False


Answer 8:

我会去更多的touple选项,做了测试,使用LooseVersion,我得到在我的测试中第二大的一个,(可能会做一些wront因为是使用该库我的第一次)

import itertools
from distutils.version import LooseVersion, StrictVersion

lista_de_frameworks = ["1.1.1", "1.2.5", "10.5.2", "3.4.5"]

for a, b in itertools.combinations(lista_de_frameworks, 2):
    if LooseVersion(a) < LooseVersion(b):
        big = b
print big

list_test = []
for a in lista_de_frameworks:
    list_test.append( tuple(map(int, (a.split(".")))))

print max(list_test)

这是我得到了什么:

3.4.5松散

(10,5,2)和与所述touples



文章来源: How do I compare version numbers in Python?