在从事C ++项目时,我一直在寻找第三方库,而不是我的核心业务。我找到了一个非常好的库,完全按照需要做了,但它是用Python编写的。我决定尝试使用Boost.Python库在C ++中嵌入Python代码。
C ++代码看起来像这样:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module((handle<>(borrowed(PyImport_AddModule("__main__")))));
object name_space = module.attr("__dict__");
object ignored = exec("from myModule import MyFunc\n"
"MyFunc(\"some_arg\")\n",
name_space);
std::string res = extract<std::string>(name_space["result"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
(非常)简化版的Python代码如下所示:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
print result
现在的问题是:
'MyFunc'执行得很好,我可以看到'结果'的打印。
我不能做的是从C ++代码中读取'结果'。 extract命令永远不会在任何命名空间中找到“结果”。
我尝试将'结果'定义为全局,我甚至尝试返回一个元组,但我无法让它工作。
首先,将您的功能更改为 return
价值。 print
因为你想要获得价值,所以会使事情复杂化。假设你的 MyModule.py
看起来像这样:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
现在,要做你想做的事,你必须超越基本的嵌入,就像 文件说。以下是运行您的函数的完整代码:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pArg, *pResult;
int i;
Py_Initialize();
pName = PyString_FromString("MyModule.py");
/* Error checking of pName left out as exercise */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "MyFunc");
/* pFunc is a new reference */
if (pFunc) {
pArgs = PyTuple_New(0);
pArg = PyString_FromString("some parameter")
/* pArg reference stolen here: */
PyTuple_SetItem(pArgs, 0, pArg);
pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pResult != NULL) {
printf("Result of call: %s\n", PyString_AsString(pResult));
Py_DECREF(pResult);
}
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");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load module");
return 1;
}
Py_Finalize();
return 0;
}
首先,将您的功能更改为 return
价值。 print
因为你想要获得价值,所以会使事情复杂化。假设你的 MyModule.py
看起来像这样:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
现在,要做你想做的事,你必须超越基本的嵌入,就像 文件说。以下是运行您的函数的完整代码:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pArg, *pResult;
int i;
Py_Initialize();
pName = PyString_FromString("MyModule.py");
/* Error checking of pName left out as exercise */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "MyFunc");
/* pFunc is a new reference */
if (pFunc) {
pArgs = PyTuple_New(0);
pArg = PyString_FromString("some parameter")
/* pArg reference stolen here: */
PyTuple_SetItem(pArgs, 0, pArg);
pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pResult != NULL) {
printf("Result of call: %s\n", PyString_AsString(pResult));
Py_DECREF(pResult);
}
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");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load module");
return 1;
}
Py_Finalize();
return 0;
}
根据ΤΖΩΤΖΙΟΥ,Josh和Nosklo的回答我终于使用boost.python了解它:
蟒蛇:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
C ++:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module = import("__main__");
object name_space = module.attr("__dict__");
exec_file("MyModule.py", name_space, name_space);
object MyFunc = name_space["MyFunc"];
object result = MyFunc("some_args");
// result is a dictionary
std::string val = extract<std::string>(result["val"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
一些要点:
- 我将'exec'更改为'exec_file'了
方便,它也适用
普通'执行'。
- 失败的主要原因是 一世
没有传递“本地”name_sapce
'exec'或'exec_file' - 现在是这样
通过传递name_space两次来修复。
- 如果python函数返回
unicode字符串,它们不是
可转换为'std :: string',所以我
不得不为所有python字符串添加后缀
用'.encode('ASCII','忽略')'。
我想你需要的是 PyObject_CallObject(<py function>, <args>)
,它返回您调用为PyObject的函数的返回值,或者 PyRun_String(<expression>, Py_eval_input, <globals>, <locals>)
它评估单个表达式并返回其结果。
您应该能够从MyFunc返回结果,然后结果将在您当前称为“忽略”的变量中结束。这消除了以任何其他方式访问它的需要。