Nous allons apprendre à utiliser une fonction écrite dans un code C++ dans un script Python. Attention, il ne s'agit pas d'interpréter du C++ dans Python, mais juste d'appeler des fonctions qui sont codées sous une certaine forme que nous verrons bientôt.
Mais tout d'abord, il faut comprendre le mécanisme des
modules en Python. Vous le connaissez sûrement, mais il est bon de se le rappeler. En effet, les fonctions ne seront utilisables par l'interpréteur Python si et seulement si vous les déclarez dans un module.
En Python, voici un exemple de code utilisant un module :
Code : Python | import math #On importe le module
print str(math.cos(0))
|
A présent, nous pouvons coder une fonction que nous intégrerons plus tard dans un module. Nous allons créer une fonction qui prend en argument un nombre et qui en retourne le carré. En C++ "pur", nous aurions écrit :
Code : C++ | int carre(int n)
{
return n*n;
}
|
Sachez que
toutes les fonctions Python doivent retourner un
pointeur de type
Py0bject.
Mais si on ne veut rien retourner ?
Dans ce cas, nous allons retourner l'équivalent de
None
:
Py_None.
Nos fonctions devront comporter
deux arguments : deux
pointeurs de type
PyObject.
Le premier argument ne sera utile que s'il s'agit d'une méthode (dans une classe, donc) sinon elle vaudra
NULL
: c'est la variable
self que l'on retrouve en Python comme ceci :
Code : Python | class Test:
def __init__(self):
self.x=0
|
L'autre argument représente les arguments sous forme de tuple. Déjà, voyons le prototype de notre fonction :
Code : C++ | PyObject *carre(PyObject *self,PyObject *args);
|
Maintenant, il faut savoir extraire les arguments contenus dans la variable
args.
Nous allons utiliser une fonction qui peut s'apparenter à
scanf :
int PyArg_ParseTuple(PyObject *args, const char *format, ...);
Cependant, le contenu de la variable
format sera différent du format que l'on a avec
scanf.
Par exemple, pour une chaîne, avec
scanf nous utilisons
"%s"
, alors qu'avec
PyArg_ParseTuple nous utiliserons
"s"
.
Voici une petite liste de types (la complète se trouve
ici) :
- s : chaîne de caractères
- z : comme s, sauf que la valeur peut être NULL
- b : octet non signé (unsigned char
)
- c : caractère (char
)
- h : short int
- H : unsigned short int
- i : int
- I : unsigned int
- f : float
- d : double
- o : un objet de type quelconque sans cast
Par exemple, si vous voulez récupérer un
int
, un
float
et un
char
, il faudra faire :
Code : C++ | int entier;
float flottant;
char caractere;
PyArg_ParseTuple(args,"ifc",&entier,&flottant,&caractere);
|
Pour les formats "s" et "z", vous pouvez rajouter une "#" pour demander la longueur de la chaîne. N'oubliez pas de rajouter dans les "..." un pointeur vers un entier. Comme ceci :
Code : C++ | char *chaine;
int longueur;
PyArg_ParseTuple(args,"s#",&chaine,&longueur);
|
Autre différence avec
scanf : il faut mettre le signe '&' même devant une chaîne de caractère, sinon c'est l'erreur de segmentation assurée

!
Pour la valeur de retour, nous allons utiliser le procédé inverse : on donne le contenu du tuple qui sera compilé en un pointeur de type
PyObject grâce à la fonction
PyObject* Py_BuildValue(const char *format, ...);
.
Par exemple, pour retourner la variable
retour de type
int
, on fera :
Code : C++ | int resultat=42;
return Py_BuildValue("i",resultat);
|
Donc revenons à nos moutons. Il faut créer une fonction qui retourne le nombre passé en argument au carré.
A vos claviers

!
Petite correction :
Secret (cliquez pour afficher)Code : C++ | PyObject *carre(PyObject *self, PyObject *args)
{
int x=0;
PyArg_ParseTuple(args,"i",&x); //On récupère le nombre passé en argument
return Py_BuildValue("i",x*x); //On retourne le nombre au carré
}
|
Et ce n'est pas tout

!
Pour utiliser cette fonction via un script Python, il va falloir créer notre module. Vous l'appelez comme vous le voulez (pour moi ce sera "mathC").
Notre module sera contenu dans un tableau de type
PyMethodDef défini comme ceci :
Code : C++ | PyMethodDef module_mathC[]={{"nom_de_la_fonction",fonction,METH_VARARGS,NULL},
{NULL,NULL,0,NULL}};
|
Expliquons cette instruction. Chaque méthode doit être définie par un tableau sous la forme :
- Nom de la fonction : const char*
- Callback vers la fonction
- Type d'arguments (on va laisser à METH_VARARGS ; pour une liste complète voir ici)
- Une chaîne de caractères qui ne nous sert à rien, nous la laisserons à NULL
Ensuite, le module est un tableau de méthodes. Mais il faut mettre une méthode vide (
{NULL,NULL,0,NULL}
) sinon vous vous retrouverez avec une belle erreur lors de l'exécution

...
Dernière étape (enfin

) : initialiser le module. Nous utiliserons la fonction
PyObject* Py_InitModule(char *nom, PyMethodDef *methodes);
où
name est le nom du module à créer et
méthodes votre tableau de méthodes (ici
module_mathC) :
Code : C++ | Py_InitModule("mathC",module_mathC);
|
En récapitulant, on obtient :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #include <cstdlib>
#include <Python.h>
PyObject *carre(PyObject *self,PyObject *args);
int main(int argc,char *argv[])
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyMethodDef module_mathC[]={{"carre",carre,METH_VARARGS,NULL},
{NULL,NULL,0,NULL}};
Py_InitModule("mathC",module_mathC);
system("pause");
return 0;
}
PyObject *carre(PyObject *self,PyObject *args)
{
int x=0;
PyArg_ParseTuple(args,"i",&x);
return Py_BuildValue("i",x*x);
}
|
Maintenant, il faut aller dans le code en Python. Il faut importer le module. Vous avez différents choix :
Code : Python | import mathC
#Ou
from mathC import carre
#Ou encore
from mathC import *
|
Sachant que dans le premier cas, pour accéder à la fonction
carre, il faudra écrire
mathC.carre
, et dans les deux autres il faudra écrire
carre
tout simplement.
Voici un exemple de script :
Code : Python | from mathC import *
x=input("Entrez un nombre : ")
print "Voici son carre : "+str(carre(x))
|
Si vous l'enregistrez dans un fichier .py, vous pouvez le lancer, mais vous aurez une erreur disant que le module "mathC" n'existe pas. Par contre, si vous exécutez ce fichier via la fonction
run_py (que nous avions créée auparavant)
après l'appel à Py_InitModule, le code s'exécutera. On vous demandera d'entrer un nombre, puis son carré sera affiché.
Simple, non

?