- HPy est une nouvelle API pour étendre Python en C
- utilise
#include <hpy.h> au lieu de #include <Python.h>
Avantages de HPy
- Zéro surcoût sur CPython : les extensions écrites avec HPy s’exécutent à la même vitesse que les extensions « classiques »
- Plus rapide sur les implémentations alternatives : fonctionne plus vite sur PyPy, GraalPy, etc.
- Binaire universel : les extensions compilées avec l’ABI universelle de HPy peuvent être chargées sans modification sur CPython, PyPy, GraalPython, etc.
- Chemin de migration pour cohabiter avec l’ancienne C-API : il est possible de mélanger les appels à l’ancienne C-API et ceux de l’API HPy. Une fois tout le code migré, il peut être compilé en binaire universel fonctionnant sur toutes les versions de CPython, ainsi que sur PyPy ou GraalPy
- Mode debug : permet d’identifier facilement les fuites mémoire, les durées de vie incorrectes des objets, les usages incorrects de l’API, etc.
- Meilleure API : conçue pour dépasser les limites de l’API Python/C standard, produire des extensions plus cohérentes et de meilleure qualité, et rendre les bugs moins probables
- Capacité d’évolution : comme bien résumé dans la PEP 620, l’API Python/C standard expose de nombreux détails d’implémentation internes, ce qui complique l’évolution de l’API C. HPy évite ce problème en masquant tous les détails internes d’implémentation
État actuel
- HPy est en développement actif. La version 0.9.0 est la dernière alpha, mais le projet devrait bientôt sortir de cette phase et vise une release stable
- L’ABI de HPy est désormais jugée suffisamment stable pour permettre d’assurer la compatibilité binaire ascendante et descendante dans les prochaines releases
- L’API couvrirait désormais suffisamment de cas d’usage pour migrer des packages importants (voir notamment le port de
numpy)
- Un guide de portage et une documentation étendue sont également fournis, en particulier une référence API
- Le projet reste toujours ouvert aux discussions de design et aux nouvelles exigences
Extensions compatibles HPy
- ultrajson-hpy : premier vrai module porté vers HPy
- piconumpy : comme son nom l’indique, un module minimaliste de type numpy qui définit des types personnalisés
- numpy : l’un des objectifs ambitieux est de porter numpy vers HPy et d’utiliser cette expérience pour mieux comprendre comment concevoir l’API. Ce port est sur le point de faire passer toute la suite de tests
- matplotlib : la migration vers le mode universel n’est pas encore totalement achevée, notamment en raison de sa dépendance à NumPy. HPy fournit une API de compatibilité legacy permettant de continuer à appeler les fonctions de l’ancienne C-API et d’exécuter avec succès la suite de tests
- kiwi-solver : une dépendance de Matplotlib, entièrement portée en mode universel
Avis de GN⁺
- HPy est un projet très prometteur qui dépasse les limites de l’API Python/C et offre une meilleure extensibilité ainsi qu’une meilleure portabilité
- Son potentiel d’amélioration des performances est particulièrement séduisant sur les implémentations alternatives de Python comme PyPy et GraalPy
- Même si la migration depuis l’ancienne C-API peut être difficile, HPy propose un chemin de migration progressif qui rend ce processus beaucoup plus gérable
- Lors de l’adoption de HPy, il faut prendre en compte l’intégration avec les systèmes de build et pipelines de distribution existants, l’acceptation par les projets upstream, ainsi que la maturité et la stabilité de HPy lui-même
- Parmi les autres projets ayant des objectifs proches de HPy, on peut citer Cython et PyO3 en Rust. Ils diffèrent toutefois de HPy en ce qu’ils utilisent des langages de plus haut niveau au lieu de la C-API bas niveau
1 commentaires
Commentaires sur Hacker News
La partie la plus pénible lorsqu’on travaille avec l’API C, c’est de configurer les drapeaux de compilation/édition de liens.
python3-configne fonctionne qu’au niveau du système d’exploitation et il est difficile à utiliser pour accéder aux paquets installés via pip.python3 -m venvne génère pas ce type de scripts, et anaconda/miniconda pose aussi problème. Chaque paquet pollue les scripts de build avec des appels codés en dur du typepython3 -c "import sys: print...". J’ai ouvert une PR pour ajouter un drapeaupython3 -m sysconfig --jsonà CPythonLe fait que le langage Python soit trop centré sur une seule implémentation peut menacer sa réussite à long terme. Les serveurs web, les programmes en ligne de commande et les appareils embarqués ont des besoins différents. Si ce projet réussit à remplacer l’API C de Python par une API qui n’expose pas les détails d’implémentation, il pourrait devenir plus facile de maintenir des implémentations alternatives et d’expérimenter de nouvelles technologies
Je me demande si ce projet fournit des bindings Python indépendants de la version. Actuellement, nous construisons des bindings séparément pour chaque version, ce qui consomme beaucoup de temps en CI/CD
Il serait intéressant d’avoir des benchmarks comparant les extensions HPy et les implémentations Cython/pybind11 en termes de performances et de temps de développement
Il n’est pas clair comment ce projet s’articule avec des bibliothèques comme PyBind11 ou nanobind. Pour les utiliser de la même manière, il semble qu’il faille les réécrire
Je me demande combien de nouvelles extensions écrites en C existent encore de nos jours. Je pensais que c’était surtout Boost Python, pybind et PyO3
Je publie souvent à propos de l’implémentation de bindings CPython avec un surcoût minimal, et je voudrais partager quelques recommandations, questions et inquiétudes. Il serait bon de restructurer la landing page du projet HPy ainsi que le README du dépôt. Des statistiques de soutien pour PyPy, GraalPython et d’autres runtimes Python seraient plus convaincantes
Utiliser un objet de contexte encapsulé comme
HPyContextest utile pour l’avenir multithread de Python ou dans des environnements complexes. Mais siHPyContextest redirigé vers le singleton de CPython, cela ne résout pas le problèmeLes benchmarks de 2019 mentionnent la convention d’appel
METH_FASTCALLde CPython, mais elle n’est pas comparée. Si les performances vous intéressent, il vaut mieux parser directement les arguments depuis le tuple sans formateur de chaîneJe me demande s’il existe en Python quelque chose de simple comme le ffi de luajit, qui permet de fournir des en-têtes C et de charger une bibliothèque partagée pour rendre des structures utilisables et appeler des fonctions
Je m’intéresse à l’appel de Go depuis Python, et gopy génère des bindings Python pour cgo. HPy<->cgo pourrait avoir moins de surcoût
Imaginez à quel point l’écosystème Python serait différent si ce travail avait été achevé il y a 20 ans