90 votes

Appel d'une méthode python à partir de C/C++, et extraction de sa valeur de retour

J'aimerais appeler une fonction personnalisée qui est définie dans un module Python de C. J'ai un code préliminaire pour le faire, mais il imprime juste la sortie à stdout.

mytest.py

import math

def myabs(x):
    return math.fabs(x)

test.cpp

#include <Python.h>

int main() {
    Py_Initialize();
    PyRun_SimpleString("import sys; sys.path.append('.')");
    PyRun_SimpleString("import mytest;");
    PyRun_SimpleString("print mytest.myabs(2.0)");
    Py_Finalize();

    return 0;
}

Comment puis-je extraire la valeur de retour en C double et l'utiliser en C ?

33voto

kilojoules Points 123

Voici un exemple de code que j'ai écrit (avec l'aide de diverses sources en ligne) pour envoyer une chaîne à un code Python, puis retourner une valeur.

Voici le code C call_function.c :

#include <Python.h>
#include <stdlib.h>
int main()
{
   // Set PYTHONPATH TO working directory
   setenv("PYTHONPATH",".",1);

   PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;


   // Initialize the Python Interpreter
   Py_Initialize();


   // Build the name object
   pName = PyString_FromString((char*)"arbName");

   // Load the module object
   pModule = PyImport_Import(pName);


   // pDict is a borrowed reference 
   pDict = PyModule_GetDict(pModule);


   // pFunc is also a borrowed reference 
   pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");

   if (PyCallable_Check(pFunc))
   {
       pValue=Py_BuildValue("(z)",(char*)"something");
       PyErr_Print();
       printf("Let's give this a shot!\n");
       presult=PyObject_CallObject(pFunc,pValue);
       PyErr_Print();
   } else 
   {
       PyErr_Print();
   }
   printf("Result is %d\n",PyInt_AsLong(presult));
   Py_DECREF(pValue);

   // Clean up
   Py_DECREF(pModule);
   Py_DECREF(pName);

   // Finish the Python Interpreter
   Py_Finalize();


    return 0;
}

Voici le code Python, dans le fichier arbName.py :

 def someFunction(text):
    print 'You passed this Python program '+text+' from C! Congratulations!'
    return 12345

J'utilise la commande gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.out pour exécuter ce processus. Je suis sur Redhat. Je recommande d'utiliser PyErr_Print() ; pour la vérification des erreurs.

11voto

Mark Tolonen Points 32702

Un exemple complet d'appel d'une fonction Python et de récupération du résultat se trouve surhttp://docs.python.org/release/2 .6.5/extending/embedding.html#pure-embedding :

#include <Python.h>

int
main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc;
    PyObject *pArgs, *pValue;
    int i;

    if (argc < 3) {
        fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
        return 1;
    }

    Py_Initialize();
    pName = PyString_FromString(argv[1]);
    /* Error checking of pName left out */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, argv[2]);
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(argc - 3);
            for (i = 0; i < argc - 3; ++i) {
                pValue = PyInt_FromLong(atoi(argv[i + 3]));
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                }
                /* pValue reference stolen here: */
                PyTuple_SetItem(pArgs, i, pValue);
            }
            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
    Py_Finalize();
    return 0;
}

6voto

lama12345 Points 169

Pour éviter le fichier .py supplémentaire comme dans les autres réponses, vous pouvez simplement récupérer le module __main__, qui est créé par le premier appel à PyRun_SimpleString :

PyObject *moduleMainString = PyString_FromString("__main__");
PyObject *moduleMain = PyImport_Import(moduleMainString);

PyRun_SimpleString(
    "def mul(a, b):                                 \n"\
    "   return a * b                                \n"\
);

PyObject *func = PyObject_GetAttrString(moduleMain, "mul");
PyObject *args = PyTuple_Pack(2, PyFloat_FromDouble(3.0), PyFloat_FromDouble(4.0));

PyObject *result = PyObject_CallObject(func, args);

printf("mul(3,4): %.2f\n", PyFloat_AsDouble(result)); // 12

1voto

Vous devez d'une manière ou d'une autre extraire la méthode python et l'exécuter avec PyObject_CallObject(). Pour ce faire, vous pouvez fournir à Python un moyen de définir la fonction, comme le fait l'exemple de Tutoriel Python d'extension et d'intégration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X