Создание и вызов функции python из строки через C API
можно ли загрузить функцию python из строки, а затем вызвать эту функцию с аргументами и получить возвращаемое значение?
я использую API python C для запуска кода python из моего приложения c++. Я могу загрузить модуль из файла, используя PyImport_Import
, получить объект функции, что с помощью PyObject_GetAttrString
, и вызовите функцию с PyObject_CallObject
. Что я хотел бы сделать, так это загрузить модуль / функцию из строки вместо файла. Есть ли какой-то эквивалент PyImport_Import
что позволит мне передать ему строку вместо файла? Мне нужно передать аргументы вызываемой функции, и мне нужен доступ к возвращаемому значению, поэтому я не могу просто использовать PyRun_SimpleString
.
Edit:
я нашел это решение после включения PyRun_String
. Я создаю новый модуль, получая его объект словаря, передавая его по вызову PyRun_String
чтобы определить функцию в моем новом модуле, а затем получить объект функции для этого нового создана функция и вызов ее через PyObject_CallObject
, передавая мои args. Вот что я нашел, чтобы решить мою проблему:
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):ntprint 5 * xntreturn 77n", 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: %ldn", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pNewMod);
Py_Finalize();
return 0;
}
вот остальная часть моего первоначального поста, оставленная для потомков:
вот что я делал первоначально:
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 nulln");
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: %ldn", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pModule);
Py_Finalize();
return 0;
}
и atest.py
:
def doStuff( x):
print "X is %dn" % x
return 2 * x
2 ответов
PyRun_String
в Python C API, вероятно, то, что вы ищете. Смотри:http://docs.python.org/c-api/veryhigh.html
ответ, содержащийся в вопросе, отличный, но у меня были небольшие проблемы с его использованием с Python 3.5, поэтому, чтобы сохранить кого - либо еще, делая то, что я сделал, ниже немного отредактированная версия, которая, кажется, отлично работает для этой версии Python по крайней мере:
#include <Python.h>
int main(void)
{
PyObject *pArgs, *pValue, *pFunc, *pModule, *pGlobal, *pLocal;
Py_Initialize();
pGlobal = PyDict_New();
//Create a new module object
pModule = PyModule_New("mymod");
PyModule_AddStringConstant(pModule, "__file__", "");
//Get the dictionary object from my module so I can pass this to PyRun_String
pLocal = PyModule_GetDict(pModule);
//Define my function in the newly created module
pValue = PyRun_String("def blah(x):\n\ty = x * 5\n\treturn y\n",
Py_file_input, pGlobal, pLocal);
//pValue would be null if the Python syntax is wrong, for example
if (pValue == NULL) {
if (PyErr_Occurred()) {
PyErr_Print();
}
return 1;
}
//pValue is the result of the executing code,
//chuck it away because we've only declared a function
Py_DECREF(pValue);
//Get a pointer to the function I just defined
pFunc = PyObject_GetAttrString(pModule, "blah");
//Double check we have actually found it and it is callable
if (!pFunc || !PyCallable_Check(pFunc)) {
if (PyErr_Occurred()) {
PyErr_Print();
}
fprintf(stderr, "Cannot find function \"blah\"\n");
return 2;
}
//Build a tuple to hold my arguments (just the number 4 in this case)
pArgs = PyTuple_New(1);
pValue = PyLong_FromLong(4);
PyTuple_SetItem(pArgs, 0, pValue);
//Call my function, passing it the number four
pValue = PyObject_CallObject(pFunc, pArgs);
fprintf(stdout, "Returned value: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_Finalize();
return 0;
}