skip to content

What does sys.implementation tell you that sys.version_info does not?

level: middleimportance: nice to knowfreq 18%

answer

  1. Language version and interpreter are two facts
  2. One field is lowercase, one is display text
  3. It also names the cached bytecode tag
  4. PEP 421 added it to sys
  5. The name field reads 'cpython'

basics

~20 s

sys.version_info says which language version is implemented; sys.implementation says which interpreter implements it. It carries a lowercase implementation name such as cpython, that project's own version, and the tag used in cached bytecode file names.

solid answer

~40 s

The two answer different questions. `sys.version_info` is the *language* version the running interpreter claims to implement. `sys.implementation`, added by PEP 421, describes the *interpreter*: a lowercase `name` (`'cpython'`), a `version` for the implementation itself, a matching hex version, and a `cache_tag` such as `'cpython-314'` that appears in cached bytecode filenames. On CPython the implementation version equals `sys.version_info`; on another implementation it is that project's own release number, which is not the language version — a common surprise. `platform.python_implementation()` returns a capitalized display string derived from the `sys.version` banner, so compare the lowercase `name` field when you need a machine-readable value. Branch on it only for genuinely implementation-specific behaviour, such as relying on prompt refcount-based cleanup.

code

python · 8 lines
python
import sys
import platform

impl = sys.implementation
print(impl.name)                          # 'cpython'
print(platform.python_implementation())   # 'CPython'
print(impl.cache_tag)                     # 'cpython-314'
print(tuple(impl.version)[:3])            # (3, 14, 0)

go deeper

for a junior

Know that the running interpreter can be asked two separate questions — which language version it implements, and which interpreter it is — and that sys has an attribute for each.

for a middle

Be able to name the fields and the casing trap: the structured name is lowercase, while platform.python_implementation returns a capitalized display string parsed out of the version banner.

for a senior

Show judgement about when an implementation branch is legitimate — refcount-timing assumptions, native fast paths, calibrated performance tests — and when it is really a missing feature probe wearing a disguise.

for a principal

Own the portability stance: whether the codebase commits to CPython semantics outright, or pays the ongoing cost of staying implementation-neutral, and where that promise is actually verified.

## Two orthogonal questions "Which Python is this?" hides two questions that people routinely collapse into one: 1. **Which language version is implemented?** That is `sys.version_info` — the syntax and standard library you can expect. 2. **Which interpreter is implementing it?** That is `sys.implementation`. CPython is not the only interpreter that runs Python source, and a second implementation can be at, say, language level 3.11 while its own product version is something completely different. Code that reads a version number and concludes "CPython" has answered a question it never asked. ## What sys.implementation carries `sys.implementation` arrived in 3.3 with PEP 421 as the single, machine-readable place to ask about the interpreter. Its documented fields are: - **`name`** — a lowercase identifier for the implementation. On CPython it is exactly `'cpython'`. The lowercase is deliberate and load-bearing: comparisons should be `== "cpython"`, never `== "CPython"`. - **`version`** — a version-info-style named tuple giving the *implementation's* own version. On CPython this is identical to `sys.version_info`. On an implementation whose product version is tracked separately, it is that number, and it will not look like a language version at all. - **`hexversion`** — the same implementation version packed into one integer, mirroring `sys.hexversion`. - **`cache_tag`** — the string embedded in cached bytecode filenames, `'cpython-314'` on CPython 3.14, which is how two interpreters can share a source tree without stepping on each other's compiled files. It is `None` on an implementation that does not cache bytecode, so never build a path out of it by hand — `importlib.util.cache_from_source` exists for that. An implementation may attach extra attributes of its own, so treat the four above as the portable set. ```python import sys impl = sys.implementation print(impl.name) # 'cpython' print(tuple(impl.version)[:3]) print(impl.cache_tag) # 'cpython-314' ``` ## The platform module's version of the same question `platform.python_implementation()` returns a capitalized display string — `'CPython'` — and it produces that by inspecting the interpreter's own version banner rather than by reading a structured field. It is perfectly fine for a log line, a support bundle or a `--version` output. For a code branch, prefer `sys.implementation`: it is structured, it is the value the implementation itself declares, and it does not depend on the shape of a human-readable string. If you do use the `platform` function, remember its result is capitalized and its neighbours are strings too: `platform.python_version()` returns `'3.14.0'`, not a tuple. ## What is actually worth branching on Implementation checks earn their place when the behaviour you depend on is genuinely CPython's rather than the language's: - **Refcount-driven cleanup.** On CPython an object is finalised the moment its last reference goes away, which is why `open(path).read()` closes the file promptly. Implementations with a tracing collector finalise later; code that leans on the immediate behaviour is CPython-specific, and the honest fix is usually a `with` block, not a branch. - **Interpreter internals** — private `sys` attributes, bytecode layout, or the exact identity of small cached objects. - **Native extension fast paths**, where a compiled accelerator exists for one implementation only. - **Timing- or memory-sensitive tests** that are calibrated to one interpreter and should be skipped elsewhere rather than left to flake. Two limits are worth stating out loud. First, `sys.implementation` tells you the implementation, not the *build*: a free-threaded CPython 3.14 still reports `'cpython'`, and build-level questions like that are answered from `sysconfig.get_config_var`, not from the implementation name. Second, an implementation name is a poor proxy for "is this module available". If what you actually need is a module or an attribute, probe for the module or the attribute; the name of the interpreter is at best a correlated guess and at worst a branch that silently takes the wrong path on an interpreter nobody anticipated. ## The interview shape of this Nobody's offer turns on remembering the field names. What a strong answer shows is that you know the language version and the interpreter are separate facts with separate APIs, that the machine-readable name is lowercase while the `platform` display string is capitalized, and that most code should not branch on either — it should depend on documented language behaviour and probe for what it needs.

  • Why can the version field of sys.implementation differ from sys.version_info?
    Because they measure different things. sys.version_info is the language version the interpreter implements; the implementation version is the interpreter project's own release number. On CPython the two are identical, which is why the distinction is easy to miss, but on an implementation that versions its releases separately they diverge and only sys.version_info tells you which syntax and standard library you have.
  • What is the cache_tag field for, and when is it None?
    It is the identifier embedded in cached bytecode filenames — 'cpython-314' on CPython 3.14 — so several interpreters can compile the same source tree without overwriting each other's cached files. It is None on an implementation that does not write cached bytecode at all, so code should not construct those paths by hand; importlib.util.cache_from_source does it correctly.

sys.version_info is the standard a car is built to comply with; sys.implementation is the manufacturer and model that implements it.

saying these in an interview costs you the question

  • Expects the implementation name field to be capitalized
  • Thinks sys.version_info identifies the interpreter itself
  • Uses platform.system to detect the Python implementation
  • Assumes every implementation writes cached bytecode files
  • Believes a free-threaded build reports a different implementation name

context