Il salto di prestazioni
Python 3.11 è stato rilasciato il 24 ottobre 2022 con un risultato che attira più attenzione di ogni novità sintattica: è significativamente più veloce della 3.10. I benchmark pubblici di pyperformance mostrano miglioramenti medi tra 10% e 60%, con alcuni casi che arrivano a speedup superiori.
Il risultato viene dall’iniziativa Faster CPython — programma avviato a fine 2020 quando Microsoft ha assunto Mark Shannon (storico contributore CPython) e poi Guido van Rossum stesso (da Microsoft, ritornato attivo sul core). L’obiettivo dichiarato: 5x più veloce in quattro release.
PEP 659 — Specializing Adaptive Interpreter
La chiave tecnica della 3.11 è PEP 659, che introduce un interpreter che si specializza dinamicamente in base ai tipi osservati a runtime. Come funziona:
- Ogni bytecode generico (es.
BINARY_OPpera + b) dopo alcune esecuzioni viene specializzato sulla base dei tipi concreti visti (es.BINARY_OP_ADD_INT,BINARY_OP_ADD_FLOAT,BINARY_OP_ADD_UNICODE) - Ogni opcode specializzato bypassa la risoluzione dinamica di tipo, saltando direttamente all’implementazione ottimizzata
- Se i tipi cambiano, l’opcode torna alla versione generica (deoptimization)
Il risultato è un interprete che impara i pattern del codice caldo senza necessità di una compilazione JIT separata.
Altre ottimizzazioni contributo alla release:
- Frame zero-cost — chiamate di funzione con overhead drasticamente ridotto
- Faster startup — bytecode cache migliorato, interpreter startup più veloce
- Exceptions zero-cost — il
trynon ha costo se non viene sollevata eccezione (vs. costo lineare in 3.10) - Smaller objects — rappresentazione più compatta di frame, int
Exception Groups (PEP 654)
Sintassi nuova per gestire gruppi di eccezioni simultanee, utile per concurrency (asyncio.gather), parser che accumulano errori multipli:
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(task1())
tg.create_task(task2())
tg.create_task(task3())
except* ValueError as eg:
# eg è un ExceptionGroup di tutte le ValueError sollevate
for e in eg.exceptions:
print(e)
except* TypeError as eg:
# gestione separata per TypeError
...
La sintassi except* (nota come except star) cattura selettivamente dal gruppo, lasciando intatto ciò che non matcha. Integra con asyncio.TaskGroup (anch’esso nuovo in 3.11) che solleva automaticamente exception groups quando multiple task falliscono.
Fine-grained error locations (PEP 657)
Il traceback ora indica posizione precisa all’interno della riga, non solo il numero di riga:
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'
Il carato ^ indica esattamente l’espressione in errore. Cambiamento apparentemente piccolo ma di impatto pratico enorme per debugging di codice con espressioni complesse.
Typing: Self, LiteralString, variadic generics
Self type (PEP 673):
class Node:
def clone(self) -> Self: ...
# Self denota il tipo concreto del metodo corrente
LiteralString (PEP 675): type annotation per stringhe letterali, utile per prevenire SQL injection statica:
def execute_query(sql: LiteralString) -> ResultSet: ...
Variadic Generics (PEP 646): TypeVarTuple per generici con numero variabile di parametri, rilevante soprattutto per tipizzare tensor shapes in ML:
from typing import TypeVarTuple
Shape = TypeVarTuple("Shape")
class Tensor(Generic[*Shape]): ...
tomllib standard library
tomllib (PEP 680): parser TOML in standard library. Serve in particolare per gli strumenti di packaging Python che usano pyproject.toml. Rimuove la necessità di dipendere da toml/tomli per questo caso d’uso frequente.
Async & TaskGroup
La classe asyncio.TaskGroup (PEP introdotta nel 3.11) offre gestione strutturata di task concorrenti:
async def main():
async with asyncio.TaskGroup() as tg:
tg.create_task(fetch("a"))
tg.create_task(fetch("b"))
# Entrambe completate o entrambe cancellate su errore
Se un task fallisce, gli altri sono automaticamente cancellati; le eccezioni sono raggruppate in un ExceptionGroup.
Altri miglioramenti
- asyncio.timeout() context manager per timeout strutturato
- Contextvars integrati meglio con asyncio
- WASI e Emscripten come target di build (Python nel browser via Pyodide/etc.)
- tomllib in stdlib
- Rimozione di moduli deprecati (binhex)
Implicazioni pratiche
Lo speedup della 3.11 ha impatto concreto:
- Workload web (Django, FastAPI, Flask) — mediana 10-25% più veloce senza modifiche
- Data processing (pandas su dati medi) — 15-30%
- Scientific computing — dipende dal workload, spesso meno (NumPy già bypassa CPython su hot path)
- Batch job — benefici netti se compute-bound in Python puro
L’adozione 3.11 è motivata anche solo dal beneficio prestazionale — non serve nuova sintassi per guadagnare.
Nel contesto italiano
Python 3.11 si diffonde più rapidamente del solito:
- Data science team italiani — migrazione entro 6-12 mesi
- Backend web — nuovi progetti su 3.11 da inizio 2023
- Grandi SaaS italiani — rollout graduale con A/B per misurare speedup
Il tema Faster CPython continuerà in 3.12 (2023), 3.13 (2024, con free-threaded Python sperimentale) e oltre, confermando l’obiettivo di lungo periodo di migliorare sostanzialmente le prestazioni dell’interprete di riferimento.
Riferimenti: Python 3.11.0 (24 ottobre 2022). Faster CPython project (Microsoft, Mark Shannon + Guido van Rossum + team). PEP 659 (Specializing 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).
