veilletech.fr
12 sept. Feed du jour
#06 PYTHON Article

Python 3.15 range re.match au placard

Une fonction dont le nom ment finit toujours par coûter un bug.

Python 3.15 introduit re.prefixmatch(), au comportement identique à re.match() mais au nom explicite, et place cette dernière en dépréciation douce. Aucun avertissement à l'exécution, aucune suppression promise : c'est une consigne pour le code neuf, pas une migration.

2 min de lecturedébutantvidéo 1:20
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. Ce que « dépréciation douce » veut dire
  3. Le tableau à garder en tête
  4. Comment s'y prendre
  5. À retenir

Ce qui se passe

Hugo van Kemenade, release manager de Python 3.15, pose la question autrement : sans regarder la documentation, lesquelles de ces quatre lignes renvoient une correspondance ?

Python
import re
re.match("pi", "pi")      # ✅
re.match("pi", "pie")     # ✅
re.match("pi", "api")     # ❌
re.match("pi", "magpie")  # ❌

Réponse : les deux premières seulement. re.match() n'ancre qu'au début de la chaîne — pas à la fin. Un motif décrivant un nombre acceptera donc « 42abc », ce qui suffit à laisser passer une validation censée refuser.

Python 3.15 ajoute pour cela un alias au nom explicite, re.prefixmatch(), et place re.match() en dépréciation douce.

Ce que « dépréciation douce » veut dire

Le concept vient de la politique de compatibilité ascendante (PEP 387), en 2023. Une API en dépréciation douce « ne devrait plus servir à écrire du code neuf, mais reste sûre dans le code existant ». Elle demeure documentée et testée, n'évolue plus, n'émet aucun avertissement et n'est pas promise à la suppression. La documentation est claire sur ce point : le nom match() ne disparaîtra pas, « il est utilisé dans du code depuis plus de 30 ans ».

La justification tient au Zen de Python — « explicit is better than implicit » : qui lit prefixmatch() comprend le comportement, qui lit match() garde un doute.

Le tableau à garder en tête

Fonction Ancre au début Ancre à la fin Depuis Équivalent
re.search() 1.5 re.search("pi", s)
re.match() 1.5 re.search("^pi", s)
re.prefixmatch() 3.15 re.search(r"\Api", s)
re.fullmatch() 3.4 re.search(r"\Api\z", s)

Les versions sans métacaractères sont généralement un peu plus rapides.

Comment s'y prendre

Pour du code neuf : prefixmatch() si vous vouliez vraiment le demi-ancrage, sinon search() ou fullmatch(). Pour une bibliothèque qui doit tourner sur des versions antérieures à 3.15, match() reste le bon choix.

Pour bannir re.match() d'un projet, Ruff sait le faire avec la règle TID251 :

TOML
# pyproject.toml
[tool.ruff]
lint.extend-select = ["TID251"]
lint.flake8-tidy-imports.banned-api."re.match".msg = "Use re.fullmatch() or re.search() instead"

Source : Hugo van Kemenade, repéré par Simon Willison.