'How to decorate all the comparison methods inheriting from tuple

Problem

Version is being expressed as string and compared at lot of places. But then "5.10" is less than "5.2" due to ASCII comparison

Solution

Change it to tuple and then compare. Since comparison is at multiple places, I thought of having a custom class inheriting from tuple and handle the comparison myself

Proposed code

class Version(tuple):
  def __new__(self, v1):
    if not isinstance(v1, tuple):
      v1 = tuple(map(lambda x: int(x), v1.split('.')))
    return tuple.__new__(Version, v1)

  def __lt__(self, other):
    if not isinstance(other, tuple):
      other = tuple(map(lambda x: int(x), other.split('.')))
    return super().__lt__(other)

  def __repr__(self):
    return '.'.join(str(x) for x in self)

This is the code I came up with, so far, and it seems to work fine for cases like:

v1 = Version("5.10")
print(v1 < "5.2")

The question I have is, how can I avoid doing the same thing for all the other methods __le__, __gt__ etc.

There should be a more pythonic way to just massage the other argument and convert it to tuple, then call the base class corresponding method



Solution 1:[1]

As suggested in the comments, changed inheritance to composition and used total_ordering

from functools import total_ordering

@total_ordering
class Version():
  def __init__(self, v1):
    self.v1 = tuple(map(lambda x: int(x), v1.split('.')))

  def __eq__(self, other):
    if not isinstance(other, tuple):
      other = tuple(map(lambda x: int(x), other.split('.')))
    return self.v1 == other

  def __lt__(self, other):
    if not isinstance(other, tuple):
      other = tuple(map(lambda x: int(x), other.split('.')))
    return self.v1 < other

  def __repr__(self):
    return '.'.join(str(x) for x in self.v1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1