c++ - ejecutar - python en c
Llamar a un método de Python desde C/C++ y extraer su valor de retorno (7)
Aquí hay un código de muestra que escribí (con la ayuda de varias fuentes en línea) para enviar una cadena a un código de Python y luego devolver un valor.
Aquí está el código 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;
}
Aquí está el código de Python, en el archivo arbName.py
:
def someFunction(text):
print ''You passed this Python program ''+text+'' from C! Congratulations!''
return 12345
Uso el comando gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.out
gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.out
para ejecutar este proceso. Estoy en redhat. Recomiendo usar PyErr_Print (); para la comprobación de errores.
Me gustaría llamar a una función personalizada que está definida en un módulo python de C. Tengo un código preliminar para hacer eso, pero solo imprime la salida en 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;
}
¿Cómo puedo extraer el valor de retorno en un C doble y usarlo en C?
Como se explicó anteriormente, el uso de PyRun_SimpleString parece ser una mala idea.
Definitivamente debe usar los métodos provistos por la API C ( docs.python.org/c-api ).
Leer la introducción es lo primero que hay que hacer para comprender cómo funciona.
En primer lugar, debe aprender sobre PyObject que es el objeto básico para la API de C. Puede representar cualquier tipo de tipos básicos de Python (cadena, float, int, ...).
Existen muchas funciones para convertir, por ejemplo, una cadena de pitón a char * o PyFloat para duplicar.
Primero, importa tu módulo:
PyObject* myModuleString = PyString_FromString((char*)"mytest");
PyObject* myModule = PyImport_Import(myModuleString);
Luego, obteniendo una referencia a su función:
PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
Luego obteniendo su resultado:
PyObject* myResult = PyObject_CallObject(myFunction, args)
Y volviendo a un doble:
double result = PyFloat_AsDouble(myResult);
Obviamente, debe verificar los errores (ver enlace proporcionado por Mark Tolonen).
Si tienes alguna pregunta, no lo dudes. Buena suerte.
Lo he hecho usando BOOST para incrustar Python en C ++ [Este módulo C de trabajo debería ayudar]
#include <boost/python.hpp>
void main()
{
using namespace boost::python;
Py_Initialize();
PyObject* filename = PyString_FromString((char*)"memory_leak_test");
PyObject* imp = PyImport_Import(filename);
PyObject* func = PyObject_GetAttrString(imp,(char*)"begin");
PyObject* args = PyTuple_Pack(1,PyString_FromString("CacheSetup"));
PyObject* retured_value = PyObject_CallObject(func, args); // if you have arg
double retured_value = PyFloat_AsDouble(myResult);
std::cout << result << std::endl;
Py_Finalize();
}
Para evitar el archivo .py adicional como en las otras respuestas, puede recuperar el módulo __main__
, que se crea con la primera llamada a 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
Si asigna el valor de retorno a una variable, puede usar algo como PyEval_GetGlobals () y PyDict_GetItemString () para obtener el PyObject. Desde allí, PyNumber_Float puede obtener el valor que desea.
Sugiero navegar por toda la API: ciertas cosas se vuelven obvias cuando ves los diferentes métodos que están disponibles para ti, y es posible que haya un método mejor que el que he descrito.
Tienes que extraer el método python de alguna manera y ejecutarlo con PyObject_CallObject()
. Para hacerlo, puede proporcionarle a Python una forma de establecer la función, como lo hace el ejemplo del Tutorial Extender e Incorporar Python .
Un ejemplo completo de llamar a una función de Python y recuperar el resultado se encuentra en http://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;
}