Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> Python

Python - Programmation d'extensions avec C

Page PrécédentePage Suivante

Tout code que vous écrivez à l'aide d'un langage compilé tel que C, C++ ou Java peut être intégré ou importé dans un autre script Python. Ce code est considéré comme une "extension".

Un module d'extension Python n'est rien de plus qu'une bibliothèque C normale. Sur les machines Unix, ces bibliothèques se terminent généralement par .so (pour objet partagé). Sur les machines Windows, vous voyez généralement .dll (pour une bibliothèque liée dynamiquement).

Pré-requis pour l'écriture d'extensions

Pour commencer à écrire votre extension, vous aurez besoin des fichiers d'en-tête Python.

De plus, il est supposé que vous avez une bonne connaissance de C ou C++ pour écrire n'importe quelle extension Python en utilisant la programmation C.

Regardez d'abord une extension Python

Pour votre premier aperçu d'un module d'extension Python, vous devez regrouper votre code en quatre parties −

Le fichier d'en-tête Python.h

Vous devez inclure Python.h fichier d'en-tête dans votre fichier source C, qui vous donne accès à l'API Python interne utilisée pour connecter votre module à l'interpréteur.

Assurez-vous d'inclure Python.h avant tout autre en-tête dont vous pourriez avoir besoin. Vous devez suivre les instructions avec les fonctions que vous souhaitez appeler depuis Python.

Les fonctions C

La signature de l'implémentation C de vos fonctions prend toujours l'une des trois formes suivantes −

static PyObject *MyFunction( PyObject *self, PyObject *args );

static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);

static PyObject *MyFunctionWithNoArgs( PyObject *self );

Chacune des déclarations précédentes renvoie un objet Python. Il n'y a pas de vide fonction en Python comme il y en a en C. Si vous ne voulez pas que vos fonctions renvoient une valeur, renvoyez l'équivalent C de None de Python évaluer. Les en-têtes Python définissent une macro, Py_RETURN_NONE, qui le fait pour nous.

Les noms de vos fonctions C peuvent être ce que vous voulez car ils ne sont jamais vus en dehors du module d'extension. Ils sont définis comme statiques fonction.

Vos fonctions C sont généralement nommées en combinant le module Python et les noms de fonction, comme indiqué ici −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

Ceci est une fonction Python appelée func à l'intérieur du module module . Vous placerez des pointeurs vers vos fonctions C dans la table des méthodes du module qui vient généralement ensuite dans votre code source.

Le tableau de mappage des méthodes

Cette table de méthodes est un simple tableau de structures PyMethodDef. Cette structure ressemble à ceci −

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

Voici la description des membres de cette structure −

Cette table doit se terminer par une sentinelle composée de valeurs NULL et 0 pour les membres appropriés.

Exemple

Pour la fonction définie ci-dessus, nous avons le tableau de mappage de méthode suivant −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

La fonction d'initialisation

La dernière partie de votre module d'extension est la fonction d'initialisation. Cette fonction est appelée par l'interpréteur Python lors du chargement du module. Il faut que la fonction soit nommée initModule , où Module est le nom du module.

La fonction d'initialisation doit être exportée depuis la bibliothèque que vous allez construire. Les en-têtes Python définissent PyMODINIT_FUNC pour inclure les incantations appropriées pour que cela se produise pour l'environnement particulier dans lequel nous compilons. Il suffit de l'utiliser lors de la définition de la fonction.

Votre fonction d'initialisation C a généralement la structure globale suivante −

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Voici la description de Py_InitModule3 fonction −

Mettre tout cela ensemble ressemble à ce qui suit −

#include <Python.h>

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Exemple

Un exemple simple qui utilise tous les concepts ci-dessus −

#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld, 
      METH_NOARGS, helloworld_docs},
      {NULL}
};

void inithelloworld(void) {
   Py_InitModule3("helloworld", helloworld_funcs,
                  "Extension module example!");
}

Ici le Py_BuildValue La fonction est utilisée pour construire une valeur Python. Enregistrez le code ci-dessus dans le fichier hello.c. Nous verrions comment compiler et installer ce module pour qu'il soit appelé depuis le script Python.

Construire et installer des extensions

Les distutils package facilite la distribution des modules Python, à la fois des modules Python purs et des modules d'extension, de manière standard. Les modules sont distribués sous forme source et construits et installés via un script d'installation généralement appelé setup.py comme suit.

Pour le module ci-dessus, vous devez préparer le script setup.py suivant −

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['hello.c'])])

Maintenant, utilisez la commande suivante, qui effectuera toutes les étapes de compilation et de liaison nécessaires, avec les bonnes commandes et indicateurs du compilateur et de l'éditeur de liens, et copie la bibliothèque dynamique résultante dans un répertoire approprié -

$ python setup.py install

Sur les systèmes basés sur Unix, vous devrez probablement exécuter cette commande en tant que root afin d'avoir les autorisations d'écriture dans le répertoire site-packages. Ce n'est généralement pas un problème sous Windows.

Importer des extensions

Une fois que vous avez installé votre extension, vous pourrez importer et appeler cette extension dans votre script Python comme suit −

#!/usr/bin/python
import helloworld

print helloworld.helloworld()

Cela produirait le résultat suivant −

Hello, Python extensions!!

Transmettre des paramètres de fonction

Comme vous voudrez probablement définir des fonctions qui acceptent des arguments, vous pouvez utiliser l'une des autres signatures pour vos fonctions C. Par exemple, la fonction suivante, qui accepte un certain nombre de paramètres, serait définie comme ceci −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

La table de méthodes contenant une entrée pour la nouvelle fonction ressemblerait à ceci −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

Vous pouvez utiliser l'API PyArg_ParseTuple fonction pour extraire les arguments du pointeur PyObject transmis à votre fonction C.

Le premier argument de PyArg_ParseTuple est l'argument args. C'est l'objet que vous allez parser . Le deuxième argument est une chaîne de format décrivant les arguments tels que vous vous attendez à ce qu'ils apparaissent. Chaque argument est représenté par un ou plusieurs caractères dans la chaîne de format comme suit.

static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;

   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }
   
   /* Do something interesting here. */
   Py_RETURN_NONE;
}

Compiler la nouvelle version de votre module et l'importer vous permet d'invoquer la nouvelle fonction avec n'importe quel nombre d'arguments de n'importe quel type −

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

Vous pouvez probablement proposer encore plus de variantes.

Le PyArg_ParseTuple Fonction

Voici la signature standard pour PyArg_ParseTuple fonction −

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

Cette fonction renvoie 0 en cas d'erreur et une valeur différente de 0 en cas de réussite. tuple est le PyObject* qui était le deuxième argument de la fonction C. Ici formater est une chaîne C qui décrit les arguments obligatoires et facultatifs.

Voici une liste des codes de format pour PyArg_ParseTuple fonction −

Code Type C Signification
c caractère Une chaîne Python de longueur 1 devient un caractère C.
d doubler Un flottant Python devient un double C.
f flottant Un flottant Python devient un flottant C.
i entier Un int Python devient un int C.
l long Un Python int devient un C long.
L long long Un Python int devient un C long long
O ObjetPy* Obtient une référence empruntée non NULL à l'argument Python.
s car* Chaîne Python sans valeurs nulles intégrées à C char*.
s# car*+int Toute chaîne Python vers l'adresse et la longueur C.
t# car*+int Tampon à segment unique en lecture seule pour l'adresse C et la longueur.
u Py_UNICODE* Python Unicode sans valeurs nulles intégrées à C.
u# Py_UNICODE*+int Toute adresse et longueur Python Unicode C.
w# car*+int Lecture/écriture d'un tampon à segment unique vers l'adresse et la longueur C.
z car* Comme s, accepte également Aucun (définit C char* sur NULL).
z# car*+int Comme s#, accepte également Aucun (définit C char* sur NULL).
(...) conformément à ... Une séquence Python est traitée comme un argument par élément.
| Les arguments suivants sont facultatifs.
 : Format fin, suivi du nom de la fonction pour les messages d'erreur.
; Formater la fin, suivie du texte entier du message d'erreur.

Valeurs renvoyées

Py_BuildValue prend une chaîne de format un peu comme PyArg_ParseTuple Est-ce que. Au lieu de transmettre les adresses des valeurs que vous construisez, vous transmettez les valeurs réelles. Voici un exemple montrant comment implémenter une fonction d'ajout −

static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

Voici à quoi cela ressemblerait s'il était implémenté en Python −

def add(a, b):
   return (a + b)

Vous pouvez renvoyer deux valeurs de votre fonction comme suit, cela serait capturé à l'aide d'une liste en Python.

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

Voici à quoi cela ressemblerait s'il était implémenté en Python −

def add_subtract(a, b):
   return (a + b, a - b)

La Py_BuildValue Fonction

Voici la signature standard pour Py_BuildValue fonction −

PyObject* Py_BuildValue(char* format,...)

Ici formater est une chaîne C qui décrit l'objet Python à construire. Les arguments suivants de Py_BuildValue sont les valeurs C à partir desquelles le résultat est construit. Le PyObject* le résultat est une nouvelle référence.

Le tableau suivant répertorie les chaînes de code couramment utilisées, dont zéro ou plus sont jointes au format chaîne.

Code Type C Signification
c caractère Un caractère C devient une chaîne Python de longueur 1.
d doubler Un double C devient un flottant Python.
f flottant Un flottant C devient un flottant Python.
i entier Un int C devient un int Python.
l long Un C long devient un int Python.
N ObjetPy* Passe un objet Python et vole une référence.
O ObjetPy* Passe un objet Python et l'incrémente normalement.
O& convert+void* Conversion arbitraire
s car* C caractère terminé par 0* en chaîne Python, ou NULL en Aucun.
s# car*+int C char* et longueur en chaîne Python, ou NULL en Aucun.
u Py_UNICODE* Chaîne à l'échelle du C, terminée par un caractère nul vers Python Unicode, ou NULL vers Aucun.
u# Py_UNICODE*+int Chaîne et longueur à l'échelle du C pour Python Unicode, ou NULL pour Aucun.
w# car*+int Lecture/écriture d'un tampon à segment unique vers l'adresse et la longueur C.
z car* Comme s, accepte également Aucun (définit C char* sur NULL).
z# car*+int Comme s#, accepte également Aucun (définit C char* sur NULL).
(...) conformément à ... Construit un tuple Python à partir de valeurs C.
[...] selon ... Construit la liste Python à partir des valeurs C.
{...} selon ... Construit un dictionnaire Python à partir de valeurs C, alternant clés et valeurs.

Code {...} construit des dictionnaires à partir d'un nombre pair de valeurs C, alternativement des clés et des valeurs. Par exemple, Py_BuildValue("{issi}",23,"zig","zag",42) renvoie un dictionnaire comme Python {23:'zig','zag':42}.


Python

  1. Programmation orientée objet Python
  2. Instruction Python Print() :comment imprimer avec des exemples
  3. Python String strip() Fonction avec EXAMPLE
  4. Python String count() avec des EXEMPLES
  5. Python String format() Expliquer avec des EXEMPLES
  6. Méthode Python String find() avec exemples
  7. Fonctions Python Lambda avec EXEMPLES
  8. Fonction Python round() avec EXEMPLES
  9. Fonction Python map() avec EXEMPLES