通过C API从字符串创建和调用python函数
是否可以从字符串加载python函数,然后使用参数调用该函数并获取返回值?
我正在使用python C API从我的C ++应用程序中运行python代码。 我可以使用PyImport_Import
从文件加载模块,使用PyObject_GetAttrString
从中获取一个函数对象,并使用PyObject_GetAttrString
调用该函数。 我想做的是从字符串而不是文件加载模块/函数。 是否有一些等同于PyImport_Import
,它允许我传递一个字符串而不是文件? 我需要将参数传递给我正在调用的函数,我需要访问返回值,所以我不能只使用PyRun_SimpleString
。
编辑:
在打开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):\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; }
这是我原帖的其余部分,留给后人:
这是我最初做的事情: main.cpp
:
#include 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; }
和atest.py
:
def doStuff( x): print "X is %d\n" % x return 2 * x
Python C API中的PyRun_String
可能就是您正在寻找的。 请参阅: http : //docs.python.org/c-api/veryhigh.html
问题中包含的答案非常好,但我在Python 3.5中使用它有一些小问题,所以为了保存其他人做我做的事情,下面是一个略微编辑的版本,似乎至少适用于这个版本的Python:
#include 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; }