从C / C ++调用python方法,并提取其返回值
我想调用一个自定义的函数,它是从C的python模块中定义的。我有一些初步的代码来做到这一点,但它只是输出到标准输出。
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双,并在C中使用它?
如前所述,使用PyRun_SimpleString似乎是一个坏主意。
您一定要使用C-API( http://docs.python.org/c-api/ )提供的方法。
阅读介绍是了解其工作方式的第一步。
首先,你必须学习PyObject,它是C API的基本对象。 它可以表示任何types的Python基本types(string,float,int,…)。
存在许多函数来将pythonstring转换为char *或PyFloat来加倍。
首先,导入你的模块:
PyObject* myModuleString = PyString_FromString((char*)"mytest"); PyObject* myModule = PyImport_Import(myModuleString);
然后得到你的function的参考:
PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs"); PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
然后得到你的结果:
PyObject* myResult = PyObject_CallObject(myFunction, args)
回到一个双重的:
double result = PyFloat_AsDouble(myResult);
你应该明显地检查错误(比较Mark Tolonen给出的链接)。
如果您有任何问题,请不要犹豫。 祝你好运。
下面是我写的示例代码(在各种在线资源的帮助下)向Python代码发送string,然后返回一个值。
这里是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; }
以下是文件arbName.py
的Python代码:
def someFunction(text): print 'You passed this Python program '+text+' from C! Congratulations!' return 12345
我使用命令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
来运行这个过程。 我在redhat上。 我build议使用PyErr_Print(); 进行错误检查。
调用Python函数并检索结果的完整示例位于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; }
为了防止在其他答案中出现额外的.py文件,您可以只检索由第一次调用PyRun_SimpleString
创build的__main__
模块:
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
您必须以某种方式提取python方法并使用PyObject_CallObject()
运行它。 为此,可以像Python的扩展和embedded教程那样为Python提供一种设置函数的方法。
如果将返回值赋给variables,那么可以使用PyEval_GetGlobals()和PyDict_GetItemString()来获取PyObject。 从那里,PyNumber_Float可以得到你想要的值。
我build议浏览整个API–当你看到可用的不同方法时,某些事情会变得很明显,可能比我所描述的方法更好。
我已经使用BOOST来embeddedPython到C ++ [这个工作的C模块应该帮助]
#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(); }