¿Es posible cargar una función python desde una cadena y luego llamar a esa función con argumentos y obtener el valor devuelto?Crear y llamar a la función python desde la cadena a través de C API
Estoy usando la API Python C para ejecutar el código python desde dentro de mi aplicación C++. Puedo cargar un módulo desde un archivo usando PyImport_Import
, obtener un objeto de función del que usa PyObject_GetAttrString
, y llamar a la función con PyObject_CallObject
. Lo que me gustaría hacer es cargar el módulo/función de una cadena en lugar de un archivo. ¿Hay algún equivalente a PyImport_Import
que me permita pasarle una cadena en lugar de un archivo? Necesito pasar argumentos a la función que estoy llamando y necesito acceder al valor de retorno, así que no puedo usar PyRun_SimpleString
.
Editar:
He encontrado esta solución después de ser activado a PyRun_String
. Estoy creando un nuevo módulo, obteniendo su objeto de diccionario, pasando eso en una llamada al PyRun_String
para definir una función en mi nuevo módulo, luego obtengo un objeto de función para esa función recién creada y llamándola por PyObject_CallObject
, pasando my args. Esto es lo que he encontrado para resolver mi problema: main.cpp
int main()
{
PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;
PyObject *pGlobal = PyDict_New();
PyObject *pLocal;
//Create a new module object
PyObject *pNewMod = PyModule_New("mymod");
Py_Initialize();
PyModule_AddStringConstant(pNewMod, "__file__", "");
//Get the dictionary object from my module so I can pass this to PyRun_String
pLocal = PyModule_GetDict(pNewMod);
//Define my function in the newly created module
pValue = PyRun_String("def blah(x):\n\tprint 5 * x\n\treturn 77\n", Py_file_input, pGlobal, pLocal);
Py_DECREF(pValue);
//Get a pointer to the function I just defined
pFunc = PyObject_GetAttrString(pNewMod, "blah");
//Build a tuple to hold my arguments (just the number 4 in this case)
pArgs = PyTuple_New(1);
pValue = PyInt_FromLong(4);
PyTuple_SetItem(pArgs, 0, pValue);
//Call my function, passing it the number four
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Returned val: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pNewMod);
Py_Finalize();
return 0;
}
Aquí está el resto de mi post original, dejó para la posteridad:
Esto es lo que estaba haciendo originalmente: main.cpp
:
#include <Python.h>
int main()
{
PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('')");
pName = PyString_FromString("atest");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if(pModule == NULL)
{
printf("PMod is null\n");
PyErr_Print();
return 1;
}
pFunc = PyObject_GetAttrString(pModule, "doStuff");
pArgs = PyTuple_New(1);
pValue = PyInt_FromLong(4);
PyTuple_SetItem(pArgs, 0, pValue);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Returned val: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pModule);
Py_Finalize();
return 0;
}
Y atest.py
:
def doStuff(x):
print "X is %d\n" % x
return 2 * x
No es necesario dejar su publicación para la posteridad. Stack Overflow ya tiene eso cubierto. Todas las ediciones de preguntas y respuestas se archivan automáticamente, lo que podemos ver una vez que nuestros puntos alcanzan un cierto nivel. Eso nos ayuda a deshacer las malas ediciones y rastrear los cambios para comprender mejor las preguntas. Entonces, en lugar de dejarlo allí, puede eliminar sus cambios y podemos mirar el registro de edición si es necesario. Por eso, ni siquiera es necesario poner "Editar:". –