December 26, 2025

4 mois de Python de manière intensive: mon retour sur le langage

En septembre, j’ai changé de poste, et me voilà à manger du Python toute la journée. Je décrirai dans cet article mon expérience avec le langage.

Background

J’ai appris à programmer comme beaucoup en lisant des tutoriels sur internet il y a presque 20 ans, avec HTML/PHP et C.
Pendant mes études, j’ai eu l’occasion de toucher à plein de langages: Java, C, PHP (que j’aimais beaucoup car je pouvais facilement faire un site web sympa en codant comme un cochon), Ocaml, ou des choses un peu plus obscures comme VHDL (c’était ultra fun et intéressant) et Cobol.

Durant ma carrière, j’ai alterné entre des rôles de dev/lead dev et de SRE (où je codais toujours énormément: infrastructure API-first, self-service, platform engineering, tooling…​). J’ai notamment travaillé 6 ans avec Golang, 4 ans avec Clojure, j’ai été payé pour faire du Java et du Typescript, et je continue d’explorer d’autres langages sur mon temps libre. Bien sûr, nous sommes entre personnes civilisées, donc je ne mentionnerai pas shell/bash ici.

Comme tout bon sysadmin/SRE qui se respecte, j’ai fait du Python, mais à l’arrache. D’ailleurs, le second article de ce blog (2016!) explique comment développer un plugin Ansible (donc en Python) pour générer des logs structurés de l’outil et en dériver des métriques.
J’avais aussi de temps en temps l’occasion de contribuer à des codebases Python, et je n’aimais pas ça, notamment à cause de la gestion des dépendances qui était en dessous de tout.

En septembre 2025, après 3 ans et demi à bosser comme SRE, j’ai décidé de revenir sur un rôle plus proche du produit et du développement, toujours au même endroit mais dans une nouvelle équipe. Vu que c’est un rôle avec également une grosse composante AI, on est parti sur Python.

Quatre mois plus tard et avec un premier produit en prod, j’ai envie de faire un REX sur Python vu que j’ai énormément appris sur le langage pendant cette période.

Le langage

On le sait tous, Python est un langage très flexible et je le trouve très plaisant à utiliser. Je bosse sur des projets où tout est typé via mypy et c’est un vrai plaisir, notamment après 6 ans de Go (et de son typesystem merdique).

Oui oui, je persiste et signe, Python + mypy sont LARGEMENT mieux que le typesystem de Go: on a des vrais types Enum et Union (et tagged unions via Pydantic) par exemple.
Les variables optionnelles peuvent se typer T | None, ce qui est beaucoup mieux que les valeurs par défaut (ou nil pour les pointers) de Go.

On est bien sûr pas au niveau d’un Rust (ou autre langage du même style type Ocaml) sur la facilité d’utilisation des types (et des fonctions associées type pattern matching), mais c’est vraiment pas mal.

On reste sinon sur un langage objet, on a des protocoles et de l’héritage (bien pratique parfois).

La gestion d’erreur se fait via exceptions et ça me va: j’ai bossé des années sur la JVM et je préfère ça plutôt que les if err != nil de Go encore une fois.

Bref, la syntaxe est sympa, mypy est sympa (bien qu’un peu lent) et est indispensable pour bosser correctement, notamment avec des AI type Claude Code. Le code est clair et maintenable, j’aime bien.

Package manager

distutil, setuptools, pip, pip compile, pipenv, poetry…​ tout ça me faisait péter un plomb il y a quelques années. La gestion des packages en Python était un enfer sur terre, encore plus quand les gens mélangeaient les dépendances systèmes et les dépendances du projet.

On utilise uv sur nos projets, et…​ ça marche très bien. Limite je suis surpris car je m’attendais encore à des galères, mais non. C’est un énorme point de douleur qui disparait par rapport à l’époque. Pour la CI ou le déploiement en production, tout est dockerisé, donc pas de problèmes de dépendances de ce côté-là.

IDE

Je n’ai jamais réussi à configurer correctement Emacs (et LSP) pour Python, donc je suis passé sur vscode, et depuis je n’ai aucun problème. J’utilise dans l’IDE (et en dehors) ruff comme linter, qui fonctionne très bien également.

Ecosystème

On parle de Python, donc on a des libs pour tout et n’importe quoi.

On utilise des libs assez standards:

  • FastAPI pour la partie HTTP, avec gunicorn/uvicorn workers

  • SQLAlchemy (sans la partie ORM) pour la partie base de données (postgres), Alembic pour les migrations

  • Opentelemetry pour les traces (avec toutes les intégrations qui vont bien: http, sql, LLM…​), Prometheus pour certaines métriques (attendez-vous à un article sur le remplacement des métriques par les traces prochainement d’ailleurs), structlog pour les logs

  • Pydantic pour tout ce qui est "data class"

  • Quelques autres libs spécifiques au produit (boto3 pour AWS, Pydantic AI pour la partie LLM…​)

Tout fonctionne très bien (notamment la partie Opentelemetry qui est très plaisante à utiliser), mais il y a quand même quelques difficultés à relever.

L’ENORME problème que je vois est que la qualité générale de la documentation et des exemples pour construire une application prod-ready en Python laisse énormément à désirer.

La majorité des guides, tutoriels officiels inclus (type FastAPI), mettent surtout en avant comment utiliser les libs mais pas dans un contexte de production. On va donc retrouver la majorité des exemples avec des variables globales, des configurations "dev", sans aucun contenu sur des sujets comme comment faire de l’injection de dépendances proprement par exemple.

Le sentiment que j’avais en apprenant l’écosystème était vraiment "toute la doc est faite pour des étudiants qui apprennent à coder, pas pour des ingénieurs logiciels qui vont construire des produits avec des exigences de qualité importantes". C’est souvent des exemples que je qualifierai de bricolage.
Et c’est la même chose pour les autres libs (type SQLAlchemy), le tout avec souvent 3, 4, 5…​ façons de faire la même chose, ce qui est très pénible quand on est en phase d’apprentissage.

Je m’en suis vite sorti car j’avais des collègues expérimentés en Python et j’ai quand même de la bouteille, donc je détecte immédiatement les mauvais patterns dans les docs ou exemples, mais franchement un junior pourrait vite exploser en vol.

Je me demande parfois si ça ne vient pas aussi du fait que Python est beaucoup utilisé par des chercheurs, des data scientists, des sysadmin…​ où la qualité et la maintenance du code ne sont généralement pas vraiment la première priorité (ne me jetez pas la pierre mais c’est une réalité).
Bien sûr, il faut rester pragmatique et je ne suis pas moi même un extremiste du code parfait, mais franchement on voit vraiment des trucs qui font peur même dans les docs officielles.

Il y a donc beaucoup de pièges à éviter mais une fois le projet correctement initialisé et l’architecture logicielle posée, ça tourne super bien. Je trouve que les libs sont globalement de qualité, FastAPI fonctionne bien (support de Pydantic et du typage, OpenAPI automatique…​), la lib Opentelemetry pour les traces est très agréable à utiliser, pour l’instant je n’ai eu aucun problème avec la partie base de données.

async / await

Il est possible d’écrire des applications asynchrones en Python grâce au support des coroutines et des mots-clés async (pour déclarer une fonction asynchrone) et await (pour l’exécuter). Des libs comme asyncio implémentent des event loops permettant de gérer ces fonctions non bloquantes, ce qui est très intéressant pour des applications n’étant pas "CPU bound" (mais faisant majoritairement des I/O, ce qui est un cas fréquent).

Je trouve l’overhead de async/await (qui est un peu le mode par défaut dans FastAPI) gérable. L’async a l’air bien supporté par la communauté et la majorité des libs fournissent une interface synchrone et asynchrone, et il est toujours possible de trouver une solution quand ce n’est pas le cas (par exemple utiliser les threads asyncio).

Là où le bât blesse, c’est sur les stacktraces. On se moque tous de Java et de ses stacktraces géantes, mais c’est 10x pire en Python notamment avec asyncio.
Vous pouvez littéralement avoir des stacktraces de centaines de lignes qui vont dump la terre entière (contenu des objets, requêtes avec headers etc inclus) si vous ne faites pas attention (notamment si vous oubliez de gérer une exception avec FastAPI/uvicorn), comportement qu’il faut désactiver impérativement en production. C’est pour moi le plus gros point noir de l’async en Python, les erreurs sont pénibles à gérer.

Performance

Les outils comme gunicorn ou uvicorn démarrent plusieurs process Python pour un même programme.
Vous avez donc le choix de scale "verticalement" en rajoutant des process pour une instance donnée de l’application, ou horizontalement en rajoutant des replicas (qui peuvent eux-mêmes avoir un ou plusieurs process).

Je n’aime pas trop ce genre de systèmes, car par expérience avec d’autres langages utilisant des patterns similaires (coucou Ruby) je trouve que ça complexifie la partie opérationnelle et c’est souvent sujet à des bugs subtils par rapport à des approches plus classiques comme en Go (un process et multithreading/goroutines).

Je présume que tout cela vient de la contrainte du GIL de Python qui empêche de faire du vrai multithreading parallèle (même si ça va sûrement changer). C’est parfois assez pénible aussi côté code, par exemple la lib officielle Prometheus a beaucoup de limitations en mode multi process. De manière générale, il faut toujours garder en tête qu’on est en multi process notamment si on veut commencer à avoir des "singleton" uniques au niveau de l’application (ce qui ne sera pas vraiment possible, d’où les problèmes de la lib Prometheus par exemple).

Je n’ai pour l’instant pas de gros volumes en terme de requêtes par seconde sur mes applications, donc je ne parlerai pas de performance brute dans cet article.
Par contre, j’ai vite remarqué que même avec 0 charge, il faut compter > 200MB de mémoire utilisée pour chaque nouveau worker (process) ajouté. C’est beaucoup. Ce n’est pas forcément un problème si les promesses de asyncio + FastAPI sont tenues (faut vraiment que je bench mais j’espère que 500-1000 req/sec par worker pour du CRUD passe sans soucis par exemple), mais c’est quand même une valeur très élevée par rapport à Go.
Je verrai bien avec le temps si le ratio perf/coût infra n’est pas trop dégueulasse.

Conclusion

J’ai été agréablement surpris par l’avancée de l’écosystème en 10 ans. Je m’attendais sérieusement à cracher du sang, et au final…​ j’aime bien.

J’ai même envie de dire que je trouve que la productivité est meilleure en Python qu’en Go (que je pratique pour rappel depuis plus de 6 ans). Le langage est bien plus agréable, l’écosystème est vaste, Python est vraiment la lingua franca de la programmation, tout le monde sait en faire et l’AI a je pense redonné un bon coup de boost au langage.

En conclusion, il est possible que je fasse de Python mon "go-to language" à la place de Go, même pour mes projets personnels. Je suis curieux de voir si je penserai toujours la même chose quand j’aurai plus de recul, dans un an par exemple.

Tags: programming
Top of page