CPython vs Pure Python#
In CPython (the standard Python implementation), you’ll often find two versions of the same module or object:
A fast implementation in C
A fallback or reference implementation in pure Python
This happens for several important reasons:
1. Performance (C version)#
Many Python modules, especially those used frequently or in performance-critical code, are implemented in C to make them much faster.
Examples:
collections.deque(C)json→ usesjson(Python) +json._json/ujson-like C acceleratorsthreading.local→ C implementation (_thread._local) + pure Python fallback (threading.local)
The C version gives significant speed improvements, especially for low-level operations like attribute access, locking, or memory management.
2. Portability (Python version)#
CPython can run on many platforms where the C extension might not be available or cannot be compiled. A pure-Python implementation is guaranteed to run everywhere, including:
rare architectures
restricted environments (embedded systems)
platforms where compiling C extensions is difficult
So the Python version ensures broad compatibility.
3. Maintainability and clarity#
The Python version often acts as a reference implementation:
It’s easier to read and understand
It clarifies tricky semantics
It helps test and validate the C version for correctness
Example:
threading.local in Python acts as a readable reference to guide the C implementation.
4. Extensibility and fallback#
Python users can sometimes subclass or modify the Python implementation when they can’t modify the C one. Also, if the C extension fails to load, Python seamlessly falls back to the pure version.
Example: threading.local#
The CPython source includes:
Component |
Role |
|---|---|
|
Fast thread-local storage used by default |
|
Pure Python fallback + nicer API |
This design lets CPython:
use the fast C implementation in normal conditions,
but still provide a pure Python fallback that behaves the same.
CPython 3.14#
Experimental JIT Compiler#
Python 3.14 ships with an experimental JIT (Just-In-Time) compiler that can improve performance by up to 20% on some workloads. The JIT compiles frequently-executed bytecode into machine code at runtime.
# Enable JIT (opt-in via environment variable)
PYTHON_JIT=1 python my_script.py
# Check if JIT is available
python -c "import sys; print(hasattr(sys, '_jit'))"
The JIT is transparent — your code runs exactly the same, just faster for hot paths. It is disabled by default and does not affect correctness.
Deferred Evaluation of Annotations (PEP 649/749)#
Python 3.14 changes how type annotations are evaluated. Previously, annotations were evaluated eagerly at function definition time. Now they are deferred — stored as special functions and only evaluated when accessed.
# This now works without quotes (even though MyClass isn't defined yet)
def create() -> MyClass:
...
class MyClass:
pass
# Annotations are evaluated lazily when you access them
import inspect
inspect.get_annotations(create) # Evaluates at this point
Impact: Forward references in type hints work without from __future__ import annotations. Pydantic and FastAPI have already adapted to this change.
Free-Threaded Mode (PEP 779)#
See Threads vs Processes for the full explanation of Python 3.14’s GIL-free threading support.