Python 3.11: 10-60% faster, exception groups, refined tracebacks

Python 3.11 (24 October 2022): specialising adaptive interpreter (PEP 659), exception groups and except* (PEP 654), precisely-pointing tracebacks, variadic generics (PEP 646). The result of the Microsoft-backed Faster CPython initiative with Mark Shannon and Guido van Rossum.

Open SourceWebR&D PythonPython 3.11PerformanceFaster CPythonMark ShannonGuido van RossumMicrosoftOpen Source

The performance leap

Python 3.11 was released on 24 October 2022 with a result attracting more attention than any syntactic novelty: it is significantly faster than 3.10. Public pyperformance benchmarks show average improvements between 10% and 60%, with some cases reaching higher speedups.

The result comes from the Faster CPython initiative — a programme started in late 2020 when Microsoft hired Mark Shannon (longstanding CPython contributor) and then Guido van Rossum himself (at Microsoft, returned active on the core). The declared goal: 5x faster in four releases.

PEP 659 — Specialising Adaptive Interpreter

The 3.11 technical key is PEP 659, introducing an interpreter that specialises dynamically based on observed runtime types. How it works:

  • Each generic bytecode (e.g. BINARY_OP for a + b) after several executions is specialised based on concrete seen types (e.g. BINARY_OP_ADD_INT, BINARY_OP_ADD_FLOAT, BINARY_OP_ADD_UNICODE)
  • Each specialised opcode bypasses dynamic type resolution, jumping directly to the optimised implementation
  • If types change, the opcode returns to the generic version (deoptimisation)

The result is an interpreter that learns hot code patterns without needing a separate JIT compilation.

Other optimisations contribute:

  • Zero-cost frames — function calls with drastically reduced overhead
  • Faster startup — improved bytecode cache, faster interpreter startup
  • Zero-cost exceptionstry has no cost if no exception is raised (vs. linear cost in 3.10)
  • Smaller objects — more compact representation of frames, int

Exception Groups (PEP 654)

New syntax for handling simultaneous exception groups, useful for concurrency (asyncio.gather), parsers accumulating multiple errors:

try:
    async with asyncio.TaskGroup() as tg:
        tg.create_task(task1())
        tg.create_task(task2())
        tg.create_task(task3())
except* ValueError as eg:
    # eg is an ExceptionGroup of all raised ValueErrors
    for e in eg.exceptions:
        print(e)
except* TypeError as eg:
    # separate handling for TypeError
    ...

The except* syntax (known as except star) catches selectively from the group, leaving intact what does not match. Integrates with asyncio.TaskGroup (also new in 3.11) that automatically raises exception groups when multiple tasks fail.

Fine-grained error locations (PEP 657)

Tracebacks now indicate precise position within the line, not just the line number:

Traceback (most recent call last):
  File "script.py", line 10, in <module>
    result = obj.attr1.attr2.method(a, b)
             ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'attr1'

The ^ caret exactly indicates the erroneous expression. A seemingly small change but with huge practical impact for debugging code with complex expressions.

Typing: Self, LiteralString, variadic generics

Self type (PEP 673):

class Node:
    def clone(self) -> Self: ...
    # Self denotes the concrete type of the current method

LiteralString (PEP 675): type annotation for literal strings, useful for preventing static SQL injection:

def execute_query(sql: LiteralString) -> ResultSet: ...

Variadic Generics (PEP 646): TypeVarTuple for generics with variable parameter count, relevant especially for typing tensor shapes in ML:

from typing import TypeVarTuple

Shape = TypeVarTuple("Shape")
class Tensor(Generic[*Shape]): ...

tomllib standard library

tomllib (PEP 680): TOML parser in standard library. Particularly needed for Python packaging tools using pyproject.toml. Removes the need to depend on toml/tomli for this frequent use case.

Async & TaskGroup

The asyncio.TaskGroup class (PEP introduced in 3.11) provides structured concurrent task management:

async def main():
    async with asyncio.TaskGroup() as tg:
        tg.create_task(fetch("a"))
        tg.create_task(fetch("b"))
    # Both completed or both cancelled on error

If one task fails, the others are automatically cancelled; exceptions are grouped into an ExceptionGroup.

Other improvements

  • asyncio.timeout() context manager for structured timeout
  • Contextvars better integrated with asyncio
  • WASI and Emscripten as build targets (Python in browser via Pyodide/etc.)
  • tomllib in stdlib
  • Removal of deprecated modules (binhex)

Practical implications

The 3.11 speedup has concrete impact:

  • Web workloads (Django, FastAPI, Flask) — 10-25% median faster with no changes
  • Data processing (pandas on medium data) — 15-30%
  • Scientific computing — depends on workload, often less (NumPy already bypasses CPython on hot paths)
  • Batch jobs — net benefits if compute-bound in pure Python

3.11 adoption is motivated even just by performance gain — no new syntax needed to benefit.

In the Italian context

Python 3.11 diffuses more rapidly than usual:

  • Italian data science teams — migration within 6-12 months
  • Backend web — new projects on 3.11 from early 2023
  • Large Italian SaaS — gradual rollout with A/B to measure speedup

The Faster CPython theme continues in 3.12 (2023), 3.13 (2024, with experimental free-threaded Python) and beyond, confirming the long-term goal of substantially improving reference interpreter performance.


References: Python 3.11.0 (24 October 2022). Faster CPython project (Microsoft, Mark Shannon + Guido van Rossum + team). PEP 659 (Specialising Adaptive Interpreter), PEP 654 (Exception Groups), PEP 657 (fine-grained error locations), PEP 673 (Self type), PEP 675 (LiteralString), PEP 646 (Variadic Generics), PEP 680 (tomllib).

Need support? Under attack? Service Status
Need support? Under attack? Service Status