Python has four obvious built-in ways to retrieve its current version. If your software has a minimum version requirement, you'll use one of these methods to test whether the Python currently running your code is a high-enough version to do so successfully.
Three of these ways are worthless, actively-harmful traps. If you read nothing else, read this: use
The four ways are:
sys.version_infois the good way, returning a tuple of numbers, one for each component of the version
sys.versionis a terrible way, returning a string containing the full version identifier
platform.python_version()is another terrible way, also returning a string
platform.python_version_tuple()is a final and especially terrible way, returning A TUPLE OF GODDAM STRINGS FOR THE COMPONENTS
sys.version_info returns a tuple of numeric components. Well, it returns a namedtuple, but same deal. If I convert it to a plain tuple, on my system I get:
(3, 7, 12, 'final', 0)
Tuples in Python have nice sorting behavior; they'll compare against other tuples element-wise, with missing items considered as coming before present items. This means that if I write
sys.version_info >= (3, 7), it'll be true - the
7 match, then the remaining components in
sys.version mean it's slightly greater than the
(3, 7) literal.
Importantly, because this uses element-wise comparison and the elements are (mostly) numbers, it won't fail for stupid reasons, like version 3.10 coming out. If you compare
(3, 10) >= (3, 7) it correctly returns
True, because 10 is greater than 7.
platform.python_version_tuple() also returns a tuple of components, but each component is a string. Currently on my system it returns
('3', '7', '12').
If you compare it with a literal tuple, like
platform.python_version_tuple() >= ('3', '7') (note that you have to write the literal with strings, or else it'll error), it'll appear to work - you'll get back True. If the function returns
('3', '6') or
('3', '8') it also appears to do the right thing, returning
True respectively. Bump it to
('3', '9') and it's still
True, as expected. But advance to
('3', '10') and it suddenly returns
False, indicating that version 3.10 is less than version 3.7.
This is because string-wise comparison is not the same as numerical comparison. Strings compare letter-by-letter, and "1" (the first letter of "10") is indeed less than "7", and so fails the
This is a very easy mistake for end-users to make. It's an unforgiveable mistake for Python, the language, to make. Returning a tuple, indicating it's been parsed, but filling that tuple with strings when they know the components are numeric and will be used as if they were numbers, is just absolute clown-shoes behavior.
platform.python_version() just straight up return strings. Once again, naive comparison seems to work: on my system
'3.7.12 (default, Nov 11 2021, 11:50:43) \n[GCC 10.3.0]', and if you run
sys.version >= '3.7', it returns
True as expected.
Both of these fail when the version is 3.10, in the exact same way as
Always, always, ALWAYS use
sys.version_info to get the current Python version, for any purpose. Anything else will break your code for stupid reasons.