This document is for an old version of Python that is no longer supported. You should upgrade and read the Python documentation for the current stable release.

# FAQ extension/intégration

Sommaire

- FAQ extension/intégration

  - Puis-je créer mes propres fonctions en C ?

  - Puis-je créer mes propres fonctions en C++ ?

  - Écrire directement en C est difficile ; existe-t-il des alternatives ?

  - Comment puis-je exécuter des instructions quelconques Python à partir de C ?

  - Comment puis-je évaluer une expression quelconque de Python à partir de C ?

  - Comment puis-je extraire des donnés en C d’un objet Python ?

  - Comment utiliser Py_BuildValue() pour créer un tuple de longueur définie ?

  - Comment puis-je appeler la méthode d’un objet à partir de C ?

  - Comment puis-je récupérer la sortie de `PyErr_Print()` (ou tout ce qui s’affiche sur stdout/stderr) ?

  - Comment accéder à un module écrit en Python à partir de C ?

  - Comment s’interfacer avec les objets C++ depuis Python ?

  - J’ai ajouté un module en utilisant le fichier Setup et la compilation échoue ; pourquoi ?

  - Comment déboguer une extension ?

  - Je veux compiler un module Python sur mon système Linux, mais il manque certains fichiers. Pourquoi ?

  - What does « SystemError: _PyImport_FixupExtension: module yourmodule not loaded » mean?

  - Comment distinguer une « entrée incomplète » (incomplete input) d’une « entrée invalide » (invalid input) ?

  - Comment puis-je trouver les symboles g++ indéfinis `__builtin_new` ou `__pure_virtual` ?

  - Puis-je créer une classe d’objets avec certaines méthodes implémentées en C et d’autres en Python (p. ex. en utilisant l’héritage) ?

  - When importing module X, why do I get « undefined symbol: PyUnicodeUCS2* »?

## Puis-je créer mes propres fonctions en C ?

Oui, vous pouvez créer des modules intégrés contenant des fonctions, des variables, des exceptions et même de nouveaux types en C. Ceci est expliqué dans le document Extension et intégration de l’interpréteur Python.

La plupart des livres Python intermédiaires ou avancés couvrent également ce sujet.

## Puis-je créer mes propres fonctions en C++ ?

Oui, en utilisant les fonctionnalités de compatibilité C existantes en C++. Placez `extern "C" { ... }` autour des fichiers Python inclus et mettez `extern "C"` avant chaque fonction qui va être appelée par l’interpréteur Python. Les objets C++ globaux ou statiques avec les constructeurs ne sont probablement pas une bonne idée.

## Écrire directement en C est difficile ; existe-t-il des alternatives ?

Il y a un certain nombre de solutions existantes qui vous permettent d’écrire vos propres extensions C, selon ce que vous essayez de faire.

If you need more speed, Psyco generates x86 assembly code from Python bytecode. You can use Psyco to compile the most time-critical functions in your code, and gain a significant improvement with very little effort, as long as you’re running on a machine with an x86-compatible processor.

Cython and its relative Pyrex are compilers that accept a slightly modified form of Python and generate the corresponding C code. Pyrex makes it possible to write an extension without having to learn Python’s C API.

If you need to interface to some C or C++ library for which no Python extension currently exists, you can try wrapping the library’s data types and functions with a tool such as SWIG. SIP, CXX Boost, or Weave are also alternatives for wrapping C++ libraries.

## Comment puis-je exécuter des instructions quelconques Python à partir de C ?

The highest-level function to do this is `PyRun_SimpleString()` which takes a single string argument to be executed in the context of the module `__main__` and returns 0 for success and -1 when an exception occurred (including `SyntaxError`). If you want more control, use `PyRun_String()`; see the source for `PyRun_SimpleString()` in `Python/pythonrun.c`.

## Comment puis-je évaluer une expression quelconque de Python à partir de C ?

Appelez la fonction `PyRun_String()` de la question précédente avec le symbole de départ `Py_eval_input` ; il analyse une expression, l’évalue et renvoie sa valeur.

## Comment puis-je extraire des donnés en C d’un objet Python ?

Cela dépend du type d’objet. Si c’est un tuple, `PyTuple_Size()` renvoie sa longueur et `PyTuple_GetItem()` renvoie l’élément à l’index spécifié. Les listes ont des fonctions similaires, `PyListSize()` et `PyList_GetItem()`.

For strings, `PyString_Size()` returns its length and `PyString_AsString()` a pointer to its value. Note that Python strings may contain null bytes so C’s `strlen()` should not be used.

To test the type of an object, first make sure it isn’t NULL, and then use `PyString_Check()`, `PyTuple_Check()`, `PyList_Check()`, etc.

There is also a high-level API to Python objects which is provided by the so-called “abstract” interface – read `Include/abstract.h` for further details. It allows interfacing with any kind of Python sequence using calls like `PySequence_Length()`, `PySequence_GetItem()`, etc.) as well as many other useful protocols.

## Comment utiliser Py_BuildValue() pour créer un tuple de longueur définie ?

You can’t. Use `t = PyTuple_New(n)` instead, and fill it with objects using `PyTuple_SetItem(t, i, o)` – note that this « eats » a reference count of `o`, so you have to `Py_INCREF()` it. Lists have similar functions `PyList_New(n)` and `PyList_SetItem(l, i, o)`. Note that you must set all the tuple items to some value before you pass the tuple to Python code – `PyTuple_New(n)` initializes them to NULL, which isn’t a valid Python value.

## Comment puis-je appeler la méthode d’un objet à partir de C ?

La fonction `PyObject_CallMethod()` peut être utilisée pour appeler la méthode d’un objet. Les paramètres sont l’objet, le nom de la méthode à appeler, une chaîne de caractères comme celle utilisée pour `Py_BuildValue()` et les valeurs des arguments :

    PyObject *
    PyObject_CallMethod(PyObject *object, char *method_name,
                        char *arg_format, ...);

Cela fonctionne pour tous les objets qui ont des méthodes — qu’elles soient intégrées ou définies par l’utilisateur. Vous êtes responsable de « `Py_DECREF()`er » la valeur de retour à la fin.

Pour appeler, p. ex., la méthode seek d’un objet file avec les arguments 10, 0 (en supposant que le pointeur de l’objet fichier est f) :

    res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0);
    if (res == NULL) {
            ... an exception occurred ...
    }
    else {
            Py_DECREF(res);
    }

Notez que `PyObject_CallObject()` veut toujours un tuple comme liste d’arguments. Aussi, pour appeler une fonction sans arguments, utilisez « () » pour être conforme au type et, pour appeler une fonction avec un paramètre, entourez-le de parenthèses, p. ex. « (i) ».

## Comment puis-je récupérer la sortie de `PyErr_Print()` (ou tout ce qui s’affiche sur stdout/stderr) ?

Dans le code Python, définissez un objet qui possède la méthode `write()`. Affectez cet objet à `sys.stdout` et `sys.stderr`. Appelez print_error ou faites simplement en sorte que le mécanisme standard de remontée des erreurs fonctionne. Ensuite, la sortie sera dirigée vers l’endroit où votre méthode `write()` écrit.

The easiest way to do this is to use the StringIO class in the standard library.

Sample code and use for catching stdout:

    >>> class StdoutCatcher:
    ...     def __init__(self):
    ...         self.data = ''
    ...     def write(self, stuff):
    ...         self.data = self.data + stuff
    ...
    >>> import sys
    >>> sys.stdout = StdoutCatcher()
    >>> print 'foo'
    >>> print 'hello world!'
    >>> sys.stderr.write(sys.stdout.data)
    foo
    hello world!

## Comment accéder à un module écrit en Python à partir de C ?

Vous pouvez obtenir un pointeur sur l’objet module comme suit :

    module = PyImport_ImportModule("<modulename>");

Si le module n’a pas encore été importé (c.-à-d. qu’il n’est pas encore présent dans `sys.modules`), cela initialise le module ; sinon il renvoie simplement la valeur de `sys.modules["<modulename>"]`. Notez qu’il n’inscrit le module dans aucun espace de nommage — il s’assure seulement qu’il a été initialisé et qu’il est stocké dans `sys.modules`.

Vous pouvez alors accéder aux attributs du module (c.-à-d. à tout nom défini dans le module) comme suit :

    attr = PyObject_GetAttrString(module, "<attrname>");

Appeler `PyObject_SetAttrString()` pour assigner des valeurs aux variables du module fonctionne également.

## Comment s’interfacer avec les objets C++ depuis Python ?

Selon vos besoins, de nombreuses approches sont possibles. Pour le faire manuellement, commencez par lire le document « Extension et intégration ». Sachez que pour le système d’exécution Python, il n’y a pas beaucoup de différence entre C et C++ — donc la méthode pour construire un nouveau type Python à partir d’une structure C (pointeur) fonctionne également avec des objets en C++.

Pour les bibliothèques C++, voir Écrire directement en C est difficile ; existe-t-il des alternatives ?.

## J’ai ajouté un module en utilisant le fichier Setup et la compilation échoue ; pourquoi ?

Le fichier Setup doit se terminer par une ligne vide, s’il n’y a pas de ligne vide, le processus de compilation échoue (ce problème peut se régler en bidouillant un script shell, et ce bogue est si mineur qu’il ne mérite pas qu’on s’y attarde).

## Comment déboguer une extension ?

Lorsque vous utilisez GDB avec des extensions chargées dynamiquement, vous ne pouvez pas placer de point d’arrêt dans votre extension tant que celle-ci n’est pas chargée.

Dans votre fichier `.gdbinit` (ou manuellement), ajoutez la commande :

    br _PyImport_LoadDynamicModule

Ensuite, lorsque vous exécutez GDB :

    $ gdb /local/bin/python
    gdb) run myscript.py
    gdb) continue # repeat until your extension is loaded
    gdb) finish   # so that your extension is loaded
    gdb) br myfunction.c:50
    gdb) continue

## Je veux compiler un module Python sur mon système Linux, mais il manque certains fichiers. Pourquoi ?

La plupart des versions pré-compilées de Python n’incluent pas le répertoire `/usr/lib/python2.x/config/`, qui contient les différents fichiers nécessaires à la compilation des extensions Python.

Pour Red Hat, installez le RPM python-devel pour obtenir les fichiers nécessaires.

Pour Debian, exécutez `apt-get install python-dev`.

## What does « SystemError: _PyImport_FixupExtension: module yourmodule not loaded » mean?

This means that you have created an extension module named « yourmodule », but your module init function does not initialize with that name.

Every module init function will have a line similar to:

    module = Py_InitModule("yourmodule", yourmodule_functions);

If the string passed to this function is not the same name as your extension module, the `SystemError` exception will be raised.

## Comment distinguer une « entrée incomplète » (incomplete input) d’une « entrée invalide » (invalid input) ?

Parfois vous souhaitez émuler le comportement de l’interpréteur interactif Python, quand il vous donne une invite de continuation lorsque l’entrée est incomplète (par exemple, vous avez tapé le début d’une instruction « if » ou vous n’avez pas fermé vos parenthèses ou triple guillemets) mais il vous renvoie immédiatement une erreur syntaxique quand la saisie est incorrecte.

En Python, vous pouvez utiliser le module `codeop`, qui se rapproche assez du comportement de l’analyseur. Par exemple, IDLE l’utilise.

La façon la plus simple de le faire en C est d’appeler `PyRun_InteractiveLoop()` (peut-être dans un autre fil d’exécution) et laisser l’interpréteur Python gérer l’entrée pour vous. Vous pouvez également définir `PyOS_ReadlineFunctionPointer()` pour pointer vers votre fonction d’entrée personnalisée. Voir `Modules/readline.c` et `Parser/myreadline.c` pour plus de conseils.

However sometimes you have to run the embedded Python interpreter in the same thread as your rest application and you can’t allow the `PyRun_InteractiveLoop()` to stop while waiting for user input. The one solution then is to call `PyParser_ParseString()` and test for `e.error` equal to `E_EOF`, which means the input is incomplete. Here’s a sample code fragment, untested, inspired by code from Alex Farber:

    #include <Python.h>
    #include <node.h>
    #include <errcode.h>
    #include <grammar.h>
    #include <parsetok.h>
    #include <compile.h>

    int testcomplete(char *code)
      /* code should end in \n */
      /* return -1 for error, 0 for incomplete, 1 for complete */
    {
      node *n;
      perrdetail e;

      n = PyParser_ParseString(code, &_PyParser_Grammar,
                               Py_file_input, &e);
      if (n == NULL) {
        if (e.error == E_EOF)
          return 0;
        return -1;
      }

      PyNode_Free(n);
      return 1;
    }

Une autre solution est d’essayer de compiler la chaîne reçue avec `Py_CompileString()`. Si cela se compile sans erreur, essayez d’exécuter l’objet code renvoyé en appelant `PyEval_EvalCode()`. Sinon, enregistrez l’entrée pour plus tard. Si la compilation échoue, vérifiez s’il s’agit d’une erreur ou s’il faut juste plus de données — en extrayant la chaîne de message du tuple d’exception et en la comparant à la chaîne « unexpected EOF while parsing ». Voici un exemple complet d’utilisation de la bibliothèque readline de GNU (il vous est possible d’ignorer SIGINT lors de l’appel à `readline()`) :

    #include <stdio.h>
    #include <readline.h>

    #include <Python.h>
    #include <object.h>
    #include <compile.h>
    #include <eval.h>

    int main (int argc, char* argv[])
    {
      int i, j, done = 0;                          /* lengths of line, code */
      char ps1[] = ">>> ";
      char ps2[] = "... ";
      char *prompt = ps1;
      char *msg, *line, *code = NULL;
      PyObject *src, *glb, *loc;
      PyObject *exc, *val, *trb, *obj, *dum;

      Py_Initialize ();
      loc = PyDict_New ();
      glb = PyDict_New ();
      PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ());

      while (!done)
      {
        line = readline (prompt);

        if (NULL == line)                          /* Ctrl-D pressed */
        {
          done = 1;
        }
        else
        {
          i = strlen (line);

          if (i > 0)
            add_history (line);                    /* save non-empty lines */

          if (NULL == code)                        /* nothing in code yet */
            j = 0;
          else
            j = strlen (code);

          code = realloc (code, i + j + 2);
          if (NULL == code)                        /* out of memory */
            exit (1);

          if (0 == j)                              /* code was empty, so */
            code[0] = '\0';                        /* keep strncat happy */

          strncat (code, line, i);                 /* append line to code */
          code[i + j] = '\n';                      /* append '\n' to code */
          code[i + j + 1] = '\0';

          src = Py_CompileString (code, "<stdin>", Py_single_input);

          if (NULL != src)                         /* compiled just fine - */
          {
            if (ps1  == prompt ||                  /* ">>> " or */
                '\n' == code[i + j - 1])           /* "... " and double '\n' */
            {                                               /* so execute it */
              dum = PyEval_EvalCode ((PyCodeObject *)src, glb, loc);
              Py_XDECREF (dum);
              Py_XDECREF (src);
              free (code);
              code = NULL;
              if (PyErr_Occurred ())
                PyErr_Print ();
              prompt = ps1;
            }
          }                                        /* syntax error or E_EOF? */
          else if (PyErr_ExceptionMatches (PyExc_SyntaxError))
          {
            PyErr_Fetch (&exc, &val, &trb);        /* clears exception! */

            if (PyArg_ParseTuple (val, "sO", &msg, &obj) &&
                !strcmp (msg, "unexpected EOF while parsing")) /* E_EOF */
            {
              Py_XDECREF (exc);
              Py_XDECREF (val);
              Py_XDECREF (trb);
              prompt = ps2;
            }
            else                                   /* some other syntax error */
            {
              PyErr_Restore (exc, val, trb);
              PyErr_Print ();
              free (code);
              code = NULL;
              prompt = ps1;
            }
          }
          else                                     /* some non-syntax error */
          {
            PyErr_Print ();
            free (code);
            code = NULL;
            prompt = ps1;
          }

          free (line);
        }
      }

      Py_XDECREF(glb);
      Py_XDECREF(loc);
      Py_Finalize();
      exit(0);
    }

## Comment puis-je trouver les symboles g++ indéfinis `__builtin_new` ou `__pure_virtual` ?

Pour charger dynamiquement les modules d’extension g++, vous devez recompiler Python, effectuer l’édition de liens en utilisant g++ (modifiez LINKCC dans le Python Modules Makefile), et effectuer l’édition de liens de votre module d’extension avec g++ (par exemple, `g++ -shared -o mymodule.so mymodule.o`).

## Puis-je créer une classe d’objets avec certaines méthodes implémentées en C et d’autres en Python (p. ex. en utilisant l’héritage) ?

Oui, vous pouvez hériter de classes intégrées telles que `int`, `list`, `dict`, etc.

La bibliothèque Boost Python Library (BPL, http://www.boost.org/libs/python/doc/index.html) fournit un moyen de le faire depuis C++ (c.-à-d. que vous pouvez hériter d’une classe d’extension écrite en C++ en utilisant BPL).

## When importing module X, why do I get « undefined symbol: PyUnicodeUCS2* »?

You are using a version of Python that uses a 4-byte representation for Unicode characters, but some C extension module you are importing was compiled using a Python that uses a 2-byte representation for Unicode characters (the default).

If instead the name of the undefined symbol starts with `PyUnicodeUCS4`, the problem is the reverse: Python was built using 2-byte Unicode characters, and the extension module was compiled using a Python with 4-byte Unicode characters.

This can easily occur when using pre-built extension packages. RedHat Linux 7.x, in particular, provided a « python2 » binary that is compiled with 4-byte Unicode. This only causes the link failure if the extension uses any of the `PyUnicode_*()` functions. It is also a problem if an extension uses any of the Unicode-related format specifiers for `Py_BuildValue()` (or similar) or parameter specifications for `PyArg_ParseTuple()`.

You can check the size of the Unicode character a Python interpreter is using by checking the value of sys.maxunicode:

    >>> import sys
    >>> if sys.maxunicode > 65535:
    ...     print 'UCS4 build'
    ... else:
    ...     print 'UCS2 build'

The only way to solve this problem is to use extension modules compiled with a Python binary built using the same size for Unicode characters.