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 sys.version_info
.
The four ways are:
sys.version_info
is the good way, returning a tuple of numbers, one for each component of the versionsys.version
is a terrible way, returning a string containing the full version identifierplatform.python_version()
is another terrible way, also returning a stringplatform.python_version_tuple()
is a final and especially terrible way, returning A TUPLE OF GODDAM STRINGS FOR THE COMPONENTS
Deets
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 3
and 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 False
and 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 >=
check.
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.
sys.version
and platform.python_version()
just straight up return strings. Once again, naive comparison seems to work: on my system sys.version
returns '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 platform.python_version_tuple()
.
Conclusion
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.