Python 3.15 est officiellement sorti le 9 octobre 2026. Cette mise à jour majeure apporte des avancées notables tant sur le plan syntaxique que sur celui des performances d’exécution. Les imports différés explicites (lazy imports) s’attaquent directement aux lenteurs de démarrage des applications volumineuses, l’arrivée de frozendict comble une attente de longue date pour les tables de correspondances immuables, le déballage dans les compréhensions rend le code plus concis et l’introduction d’une ABI stable pour les builds sans verrou global (free-threaded) accélère l’entrée de Python dans l’ère du véritable multithreading. Découvrons en détail les principales nouveautés de cette version.
PEP 810 : Imports différés explicites (Explicit lazy imports)
Les grandes applications Python font fréquemment face à un démarrage laborieux, en grande partie causé par l’effet d’entraînement des imports de modules. Historiquement, les développeurs devaient déporter les instructions d’import au sein même des fonctions ou s’appuyer sur importlib pour charger les modules à la demande. Python 3.15 propose une réponse plus élégante et intégrée : les imports différés explicites via le mot-clé contextuel lazy.
Lorsqu’on utilise lazy import, Python ne charge pas le module instantanément : il crée un objet proxy très léger. Ce n’est qu’au moment où un attribut ou une fonction de ce module est accédé pour la première fois que le chargement complet s’effectue.
lazy import json
lazy from pathlib import Path
print("Starting up...") # json et pathlib ne sont pas encore complètement importés
data = json.loads('{"key": "value"}') # json est réellement importé lors de ce premier accès
p = Path(".") # pathlib est réellement importé lors de ce premier accès
Si le module chargé de manière différée est introuvable, l’exception n’est levée qu’au premier accès. Les développeurs disposent également de la variable d’environnement PYTHON_LAZY_IMPORTS ou de l’option en ligne de commande -X lazy_imports pour orchestrer globalement ce comportement.
PEP 814 : Nouveau type natif frozendict
Python 3.15 intègre un nouveau type de correspondance immuable : frozendict. Il hérite directement d’ object et ne dérive pas de dict. Dès lors que toutes ses clés et ses valeurs sont hachables (hashable), frozendict est lui-même hachable. frozendict conserve l’ordre d’insertion des éléments, même si cet ordre est ignoré lors des comparaisons d’égalité (==).
Cette nouveauté simplifie considérablement les scénarios nécessitant des mappages immuables, notamment pour servir de clés dans des dictionnaires ou d’éléments dans des ensembles.
>>> a = frozendict(x=1, y=2)
>>> a
frozendict({'x': 1, 'y': 2})
>>> a['z'] = 3
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
a['z'] = 3
~^^^^^
TypeError: 'frozendict' object does not support item assignment
>>> b = frozendict(y=2, x=1)
>>> hash(a) == hash(b)
True
>>> a == b
True
PEP 798 : Déballage dans les compréhensions (Unpacking in comprehensions)
Les compréhensions de listes, d’ensembles et de dictionnaires, ainsi que les expressions génératrices, acceptent désormais le déballage avec * et **. Prolongement naturel de la syntaxe introduite par la PEP 448, cette fonctionnalité simplifie grandement l’aplatissement de plusieurs itérables ou la fusion de plusieurs dictionnaires, offrant une alternative directe aux compréhensions imbriquées et à itertools.chain().
>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists] # Équivalent à [x for L in lists for x in L]
[1, 2, 3, 4, 5]
>>> sets = [{1, 2}, {2, 3}, {3, 4}]
>>> {*s for s in sets} # Équivalent à {x for s in sets for x in s}
{1, 2, 3, 4}
>>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
>>> {**d for d in dicts} # Équivalent à {k: v for d in dicts for k,v in d.items()}
{'a': 3, 'b': 2}
Les expressions génératrices fonctionnent exactement de la même manière :
>>> gen = (*L for L in lists) # Équivalent à (x for L in lists for x in L)
>>> list(gen)
[1, 2, 3, 4, 5]
PEP 661 : Nouveau type natif sentinel
Python 3.15 enrichit le module builtins avec le type sentinel, destiné à standardiser la création de valeurs sentinelles uniques disposant d’une représentation textuelle claire. Les objets sentinelles préservent leur identité lors des copies superficielles, gèrent l’opérateur d’union | dans les expressions de types et peuvent être sérialisés via pickle s’ils sont importables par module et par nom.
PEP 803 : ABI stable pour les builds free-threaded (abi3t)
Pour les builds Python en mode multithread sans verrou (free-threaded), les extensions C peuvent désormais cibler une ABI stable dédiée, baptisée abi3t. Le passage à abi3t implique quelques ajustements du code source, tels que l’adoption des API standardisées par la PEP 697 et l’utilisation du nouveau point d’entrée d’export de module PyModExport_* (PEP 793).
Les extensions ne pouvant pas migrer immédiatement vers abi3t continueront d’être compilées séparément pour l’ABI stable historique (abi3) et pour l’ABI free-threaded liée à la version (cp315t).
Recommandations de mise à niveau et points d’attention
| Critère | Description détaillée |
|---|---|
| Qui doit mettre à niveau | Les développeurs d’applications volumineuses nécessitant un démarrage rapide ; les équipes réalisant de fréquentes fusions de dictionnaires complexes ; les mainteneurs adaptant activement leurs extensions C au mode free-threaded. |
| Quand mettre à niveau | L’expérimentation de Python 3.15 peut débuter immédiatement en local et dans les environnements de test. En production, il est conseillé d’attendre la compatibilité des dépendances clés (surtout les extensions C) avec abi3t ou cp315t. |
| Points d’attention | • Les capacités de traçage de cProfile sont désormais regroupées dans le nouveau module profiling (PEP 799).• L’ancien module profile est déprécié et sera retiré dans Python 3.17.• Les instructions import dans les fichiers .pth sont discrètement dépréciées au profit des fichiers de configuration .start (PEP 829).• La famille d’API PyGILState entre en dépréciation légère (soft-deprecated) et n’évoluera plus (PEP 788). |