Ответы на этот вопрос помогли мне сравнить две строки с номерами версий и выяснить, какая версия "больше" то есть новее.

Теперь мне нужно вычислить фактическую разницу между двумя номерами версий. Главным образом, чтобы увидеть, была ли выпущена новая основная версия или только дополнительная версия.

"1.3.6" - "1.3.3" должен вернуть "0.0.3"

"5.2.0" - "4.0.0" должен вернуть "1.2.0"

Я мог бы написать функцию, которая вычисляет разницу самостоятельно (легко в теории), но было бы непросто включить все случаи, уже рассмотренные pkg_resources, как буквы между или в конце номеров версий.

Я посмотрел документальный фильм о pkg_resources, но простое вычитание не работает. Есть ли другие уже реализованные решения для этой проблемы?

Изменить: Хорошо, простое вычитание не имеет большого смысла , теперь, когда я думаю об этом. Это приведет к размыванию границ между основной и вспомогательной версиями (например, «2.1» - «1.2» = «0,9», что совсем не полезно). (Спасибо @ Джереми Бэнкс)

2
R.G. 18 Дек 2015 в 12:21

4 ответа

Лучший ответ

Вы можете сравнить каждую часть по одной:

def compare(a, b):
    a_parts = a.split('.')
    b_parts = b.split('.')
    v = ['major', 'minor', 'build']
    for i in range(3):
        diff = int(a_parts[i]) - int(b_parts[i])
        if diff is 0:
            continue
        if diff > 0:
            direction = 'ahead'
        else:
            direction = 'behind'
            diff = -diff

        return 'pkg is %s %s version %s' %  (diff, v[i], direction)
    return 'version are equal'

print compare('3.2.1', '2.0.0') # pkg is 1 major version ahead
print compare('3.2.1', '3.0.0') # pkg is 2 minor version ahead
print compare('3.2.1', '3.2.0') # pkg is 1 build version ahead
print compare('3.2.1', '3.2.1') # version are equal
print compare('3.2.1', '6.2.1') # pkg is 3 major version behind

Если номер вашей версии не стандартный (то есть: 1.2b.4321), вы можете выполнить предварительную разборку с помощью инструмента, такого как parse_version.

1
Cyrbil 18 Дек 2015 в 10:27

Вот функция, которую я только что написал, которая делает что-то вроде этого:

def diffver(v1, v2):
    v1s = map(int, v1.split('.'))
    v2s = map(int, v2.split('.'))

    for ii, (v1r, v2r) in enumerate(zip(v1s, v2s), 1):
        if v1r != v2r:
            return ii, v1r - v2r

    return ii, 0

print diffver("4.0.0", "5.2.0")
print diffver("5.1.0", "5.2.0")
print diffver("5.4.0", "5.2.0")
print diffver("5.4.0", "5.4.0")

Он печатает:

(1, -1)
(2, -1)
(2, 2)
(3, 0)

Идея состоит в том, чтобы вернуть кортеж (PART, DIFF), где PART равен 1 для основного, 2 для младшего и т. Д., А DIFF - насколько отличается эта часть. Никакая разница не дает вам ЧАСТЬ, сколько частей сравнивалось.

2
John Zwinck 18 Дек 2015 в 09:43

Может быть, немного более компактным:

def compare_versions(ver1, ver2):
    numbers1 = [int(x) for x in ver1.split('.')]
    numbers2 = [int(x) for x in ver2.split('.')]
    return '.'.join(str(v1 - v2)  for v1, v2 in zip(numbers1, numbers2))

>>> compare_versions("1.3.6", "1.3.3")
'0.0.3'    
>>> compare_versions("5.2.0", "4.0.0" )
'1.2.0'

Вариант, который на одну строку короче:

def compare_versions(ver1, ver2):
    split_dot = lambda ver: [int(x) for x in ver.split('.')]
    return  '.'.join(str(v1 - v2)  for v1, v2 in zip(split_dot(ver1), split_dot(ver2)))
0
Mike Müller 18 Дек 2015 в 10:03

Хорошо, спасибо за ваши комментарии, теперь я вижу, что не имеет смысла сравнивать номера версий в целом.

Имеет смысл сравнивать «фрагменты» всего номера версии, то есть сравнивать только первую или вторую части. Что я, вероятно, сделаю.

Более конкретно: я сначала посмотрю, есть ли разница в основной версии (первая часть). Если это так, минорная версия не имеет значения. Если это не так, я продолжу и сравню следующую часть номера версии.

Это решение все еще будет мешать включать случаи, когда номера версий включают буквы (например, «1.8.4b»), но я думаю, что нет никакого способа обойти это.

0
R.G. 18 Дек 2015 в 09:36