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('.'))
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('.'))
The constructor will silently failsfail if type(ver_str) != 'string'
is not exactly aever stringFalse
, 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"1.2.3.4.5.6"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.
The constructor silently fails if ver_str
is not exactly a string
, 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".)
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.
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("{} < {}: {}".format(ver_1, ver_2, ver_1 < ver_2))
could become simply:
print(f"{ver_1} < {ver_2}: {ver_1 < ver_2}")
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("{} < {}: {}".format(ver_1, ver_2, ver_1 < ver_2))
could become simply:
print(f"{ver_1} < {ver_2}: {ver_1 < ver_2}")