Tutoriel pour apprendre les notions avancées en Cython

Gabor Laszlo Hajba

Traducteur

Jérémy LAURENT

Ce tutoriel est la suite d'un premier sujet intitulé « Introduction au Cython » disponible ici. L'objectif est de montrer quelques utilisations de l'appel de code Python au sein d'un code écrit en C.

Commentez ♪

- Titre : Tutoriel pour apprendre les notions avancées en Cython

- Auteur : Gabor Laszlo Hajba

- Traducteur : Jérémy LAURENT

- Parution : 24 juin 2019

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2019 Gabor Laszlo Hajba. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Incorporer et compiler du code Python

- III. Conclusion

- IV. Remerciements

I - Introduction

Ce tutoriel est la suite d'un premier sujet intitulé « Introduction au Cython » disponible ici. L'objectif est de montrer quelques utilisations de l'appel de code Python au sein d'un code écrit en C. Ce tutoriel présente de façon plus détaillée certaines fonctionnalités avancées.

Nous allons écrire un exemple simple incorporant du code Python dans du code C et créant une application exécutable pouvant être lancée en incluant l'interpréteur Python, de sorte qu'il ne soit pas nécessaire d'appeler Python.

L'installation de Python 3 et d'un compilateur C seront nécessaires pour compiler le code C en exécutable, comme indiqué précédemment. Sans compilateur C, vous ne pourrez pas essayer les exemples présentés dans ce document.

Notez que l'article original a été écrit sur un environnement Mac, de sorte que les exemples peuvent ne pas fonctionner comme prévu.

NDLR L'auteur précise qu'il est possible de le contacter en cas de problèmes sur un environnement Windows.

II - Incorporer et compiler du code Python

Nous allons en premier lieu examiner le fonctionnement de l’API d’initialisation Python et du modèle de lien de chargement lors de l’incorporation de code Python dans du C ou C++.

Pour incorporer du code Python, nous allons simplement utiliser ce squelette :

1. #include <Python.h>

2. // Inclure l'en-tête de votre module ici

4. int main (int argc, char **argv) {

5. // Initialisation

6. Py_SetProgramName (argv [0]);

7. Py_Initialize ();

8. //PyInit_yourfilename(); // Initialisation pour Python 3

10. // Insérer la logique du code ici

12. Py_Finalize();

13. return 0;

14. }

Il faut s'assurer que l'inclusion de Python.h soit la première dans vos fichiers C/C++, car Python utilise lui-même de nombreux fichiers d'en-tête qui activent ou désactivent des paramètres.

Il y a ensuite une fonction principale très simple qui contient toute la logique que vous souhaitez ajouter. Il n'est, bien entendu, pas nécessaire d'écrire tout le code dans cette fonction. Vous pouvez découper le code en plusieurs fonctions et ainsi respecter de meilleures pratiques de codage,

Et comme vous pouvez le voir, il y a trois lignes d'initialisation. Les deux premières parlent d'elles-mêmes et sont identiques à chaque fois, mais la troisième doit être changée pour chaque module que vous souhaitez utiliser. Dans l'exemple ci-dessus, il est commenté et porte un nom « amusant », mais un exemple plus concret sera montré plus tard et vous permettra de mieux comprendre comment cette ligne devrait fonctionner.

Il y a deux manières d'ajouter des fonctionnalités Python au code C. La première, appelée approche « pythonique », consiste à partager des objets Python. Cette approche est fortement conseillée lorsque votre base de code est principalement du code Python. Dans ce cas, vous aurez un module natif qui appelle le code natif. L'autre solution consiste à intégrer pleinement Python et le code Python dans votre application native. Cela signifie que dans ce cas, nous avons déjà l'environnement d'exécution de Python. Dans l'autre solution, nous devions exécuter l'interpréteur Python qui appelait notre code Cython (c'est ce qui a été fait dans l'article précédent).

Maintenant que nous savons comment lier le code Python à exécuter, examinons de plus près les exemples de code suivants :

1. cdef void cython_function():

2. print('Je suis dans une fonction Cython')

4. cdef public void cython_function():

5. print('Je suis dans une fonction Cython')

L'unique différence est le mot clé « public ». Mais cela fait une différence très significative. Si nous compilons les deux avec  cythonize  nous obtenons le résultat suivant :

Comme vous pouvez le constater, le code contenant le mot clé public a également l'extension « .h » à côté de son fichier « .c ». Ce fichier d’en-tête contient une ligne qui déclare une fonction  initcythonfile_public (void)  si la version de Python est inférieure à 2. Pour Python 3, il n’y a rien de plus à faire. Pour Python 2, vous devez appeler cette méthode d’initialisation dans le code standard comme indiqué au début du chapitre avant de faire d'autres appels.

Créons maintenant notre fichier C qui appellera la fonction définie précédemment :

1. #include <Python.h>

2. #include "cythonfile_public.h"

4. int main (int argc, char ** argv) {

6. Py_SetProgramName (argv [0]);

7. Py_Initialize ();

8. PyInit_cythonfile_public();

10. // Insérer la logique du code ici

11. cython_function ();

13. Py_Finalize();

14. return 0;

15. }

La compilation de l'exemple se fait avec les étapes suivantes :

1. cython -3 cythonfile_public.pyx

2. gcc -g -fpic -c cythonfile_public.c -o cythonfile_public.o `python3.6-config --includes`

3. gcc -g -fpic -c cythontest.c -o cythontest.o `python3.6-config --includes`

4. gcc -g -o cythontest cythonfile_public.o cythontest.o `python3.6-config --libs` -L /Library/Frameworks/Python.framework/Versions/3.6/lib

La première commande compile le fichier Cython cythonfile_public.pyx en un fichier « .h » et un fichier « .c ». L'indicateur -3 indique au compilateur Cython que le code Python a été écrit avec la syntaxe Python 3 et qu'un fichier C basé sur Python 3 sera créé.

La deuxième commande compile ce fichier C, la troisième commande compile le fichier  cythontest.c  et la quatrième commande lie les deux fichiers « .o » compilés à un exécutable appelé « cythontest ».

Les paramètres appliqués, tels que python3.6-config --includes, indiquent l’emplacement des bibliothèques de l’installation Python à inclure dans le processus de compilation. Le nom python3.6-config inclut le numéro de version de l'installation Python dans le cas où vous en avez plusieurs, et que la valeur par défaut n'est pas celle-ci. Vous pouvez vérifier si python-config est suffisant pour votre ordinateur en exécutant cette commande :

1. ComputerName$ python3.6-config --includes

2. -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m

Vous pouvez voir le numéro de version dans la sortie. S'il est supérieur à 3, vous pouvez continuer. Si c'est quelque chose comme ça :

GHajba$ python-config --includes
-I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7

vous devez ajuster alors votre configuration pour qu'elle pointe vers une installation Python 3.

Le bloc de commandes de compilation présenté précédemment peut également être inclus dans un Makefile si vous ne voulez pas tout écrire à chaque fois.

Nous pouvons exécuter l’exemple d’application en exécutant le fichier exécutable créé précédemment. Cela ressemblera à ceci :

1. ComputerName$ ./cythontest

2. Je suis dans une fonction Cython

Comme vous pouvez le constater, les liens entre le code Cython et le code C fonctionnent correctement.

III - Conclusion

Dans cet article, nous avons utilisé du code Python à partir de code C avec le module Cython. Nous avons vu comment nous pouvons compiler différentes parties ensemble pour avoir un exécutable natif basé sur un code C qui appelle une fonction dans un module Cython.

IV - Remerciements

Merci à Gabor Laszlo Hajba pour son article qu’il nous a autorisés à traduire, à popo pour sa traduction, et à Chrtophe pour sa relecture.