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 ?
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 :
# 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.