Compare two version numbers in the form Major.Minor.Patch.Build to see if one is less than or greater than the other Python 3.7.0

from sys import argv
class Version:
    def __init__(self, ver_str):
        if type(ver_str) != 'string':
            ver_list = ver_str.split('.')
            self.Major = int(ver_list[0])
            self.Minor = int(ver_list[1])
            self.Patch = int(ver_list[2])
            self.Build = int(ver_list[3])

    def __repr__(self):
        return "{}.{}.{}.{}".format(self.Major, self.Minor, self.Patch, self.Build)
    def __lt__(self, other):
        if other.Major != self.Major:
            return self.Major &lt; other.Major
        elif other.Minor != self.Minor:
            return self.Minor &lt; other.Minor
        elif other.Patch != self.Patch:
            return self.Patch &lt; other.Patch

        else:
            return self.Build &lt; other.Build 

    def __gt__(self, other):
        if other.Major != self.Major:
            return self.Major &gt; other.Major
        elif other.Minor != self.Minor:
            return self.Minor &gt; other.Minor
        elif other.Patch != self.Patch:
            return self.Patch &gt; other.Patch

        else:
            return self.Build &gt; other.Build 

    def printme(self):
        print("{}.{}.{}.{}".format(self.Major, self.Minor, self.Patch, self.Build))


def main(argv):
    validate_args(argv)

    ver_1 = Version(argv[1])

    ver_2 = Version(argv[2])
    op = argv[3]

    if op == '&lt;':
        print("{} &lt; {}: {}".format(ver_1, ver_2, ver_1 &lt; ver_2))
    elif op == '&gt;':
        print("{} &gt; {}: {}".format(ver_1, ver_2, ver_1 &gt; ver_2))
    else:
        print("Incorrect operator")
        exit(-1)

def validate_args(argv):
    no_of_args = len(argv)
    if no_of_args != 4:
        print("USAGE: {} 1.1.1.1 2.2.2.2 '&lt;' or '&gt;'".format(argv[0]))
        exit(-1)
    if (len(argv[1].split('.')) != 4) or (len(argv[2].split('.')) != 4):
        print("USAGE: {} 1.1.1.1 2.2.2.2. '&lt;' or '&gt;' IMPROPER VERSION FORMAT".format(argv[0]))
        exit(-1)
    if argv[3] != '&gt;' and argv[3] != '&lt;':
        print("USAGE: {} 1.1.1.1 2.2.2.2. '&lt;' or '&gt;' IMPROPER OPERATOR".format(argv[0]))
        exit(-1)

if __name__ == '__main__':
    main(argv)
First of all, have you looked at LooseVersion and/or StrictVersion from distutils.version?  They might already provide you with exactly what you need.



General “PEP-8” Comments:

You should have a blank line after your import, after class Version, and after the def __repr__(self) method.  The blank-lines inside of __lt__ and __gt__ functions before the else: clause are inconsistent.

Your class and methods could benefit from """doc strings""".

The class members Major, Minor, Patch and Build should all be lower case.  Only class names should begin with capital letters.  Since the members should be private to the class, they should also be prefixed with an underscore.



The constructor will silently fail if type(ver_str) != 'string' is ever False, and then the instance becomes useless, as the members which are required in every other method of the class become reference errors.  There is no need to check if ver_str is a string; just try to split it, and convert the parts to integers.  If you haven’t passed in a string, the split or conversion to integers will cause an exception.  (You could add a check that the split produces exactly 4 parts, to reject a version such as "1.2.3.4.5.6".)

Fortunately (as noted by @200_success in the comments), type(ver_str) will never equal 'string', because type(...) doesn't return strings; it returns types.  The code only works because the test inverts the condition, and reads != when the intention is for the type to == a string.  The correct test would be closer to if isinstance(ver_str, str):, but again explicit type checking is an anti-pattern.

Without the explicit type checking, and using a more functional approach, the constructor could be written as a one line method.  As a side-effect of the deconstruction assignment, the version string must contain exactly 4 parts or an exception will be raised.

def __init__(self, ver_str):
    self.Major, self.Minor, self.Patch, self.Build = map(int, ver_str.split('.'))




printme() is unused and could be deleted.  If you don’t wish to delete it, at least name it using snake_case to make it more readable: print_me().  You could write the function as simply print(repr(self)) to avoid duplicating code.



__repr__(self) should actually return a string like Version("1.2.3.4"), not the string "1.2.3.4" to conform to the repr() contract.  What you have written would make a great __str__(self) method though, and you could then implement __repr__(self) using the str() method.



Inside def main(...):, you are using argv.  This is a different argv, shadowing the one you import from sys using from sys import argv.

You should avoid shadowing the imported name, by using:

import sys

# ....

if __name__ == '__main__':
    main(sys.argv)




There is no need to exit(-1) from main(), since the program will terminate anyway immediately.  exit() will terminate the Python interpreter, which can be unexpected, and can cause resources to not be properly closed.  A unit test framework will abruptly terminate, preventing recording of the test results, and preventing other unit tests from running.  In short, don’t ever use exit().  Ever.



Since you are explicitly writing for Python 3.7.0, you can use f-strings.  This means you can replace many of your .format(...) calls with a more compact, readable representation where the substitution location and value are combined.  Ie:

    print("{} &lt; {}: {}".format(ver_1, ver_2, ver_1 &lt; ver_2))


could become simply:

    print(f"{ver_1} &lt; {ver_2}: {ver_1 &lt; ver_2}")