【发布时间】:2018-11-09 19:12:39
【问题描述】:
这个问题是关于如何将 C++ 对象传递给在 (C++) 嵌入式 Python 解释器中调用的 Python 函数。
以下 C++ 类 (MyClass.h) 专为测试而设计:
#ifndef MyClassH
#define MyClassH
#include <string>
using std::string;
class MyClass
{
public:
MyClass(const string& lbl): label(lbl) {}
~MyClass(){}
string getLabel() {return label;}
private:
string label;
};
#endif
可以通过以下 Swig 接口文件生成一个暴露 C++ 类的 python 模块:
%module passmetopython
%{ #include "MyClass.h" %}
%include "std_string.i"
//Expose to Python
%include "MyClass.h"
下面是一个使用 python 模块的 Python 脚本
import passmetopython as pmtp
def execute(obj):
#This function is to be called from C/C++, with a
#MyClass object as an argument
print ("Entering execute function")
lbl = obj.getLabel();
print ("Printing from within python execute function. Object label is: " + lbl)
return True
def main():
c = pmtp.MyClass("Test 1")
retValue = execute(c)
print("Return value: " + str(retValue))
#Test function from within python
if __name__ == '__main__':
main()
这个问题是关于如何让 python execute() 函数在从 c++ 调用时以 C++ 对象作为参数工作。
编写了以下 C++ 程序来测试功能(最少的错误检查):
#include "Python.h"
#include <iostream>
#include <sstream>
#include "MyClass.h"
using namespace std;
int main()
{
MyClass obj("In C++");
cout << "Object label: \"" << obj.getLabel() << "\"" << endl;
//Setup the Python interpreter and eventually call the execute function in the
//demo python script
Py_Initialize();
//Load python Demo script, "passmetopythonDemo.py"
string PyModule("passmetopythonDemo");
PyObject* pm = PyUnicode_DecodeFSDefault(PyModule.c_str());
PyRun_SimpleString("import sys");
stringstream cmd;
cmd << "sys.path.append(\"" << "." << "\")";
PyRun_SimpleString(cmd.str().c_str());
PyObject* PyModuleP = PyImport_Import(pm);
Py_DECREF(pm);
//Now create PyObjects for the Python functions that we want to call
PyObject* pFunc = PyObject_GetAttrString(PyModuleP, "execute");
if(pFunc)
{
//Setup argument
PyObject* pArgs = PyTuple_New(1);
//Construct a PyObject* from long
PyObject* pObj(NULL);
/* My current attempt to create avalid argument to Python */
pObj = PyLong_FromLong((long) &obj);
PyTuple_SetItem(pArgs, 0, pObj);
/***** Calling python here *****/
cout<<endl<<"Calling function with an MyClass argument\n\n";
PyObject* res = PyObject_CallObject(pFunc, pArgs);
if(!res)
{
cerr << "Failed calling function..";
}
}
return 0;
}
运行上述代码时,execute() python 函数以 MyClass 对象作为参数,失败并返回 NULL。但是,输入了Python函数,在控制台输出中我可以看到输出(Entering execute function),表明传递的对象不是,确实,一个有效的MyClass 对象。
有很多关于如何将简单类型(如整数、双精度或字符串类型)从 C/C++ 传递给 Python 的示例。但是很少有例子展示如何传递一个 C/C++ 对象/指针,这有点令人费解。
上面的代码,带有一个 CMake 文件,可以从 github 上签出: https://github.com/TotteKarlsson/miniprojects/tree/master/passMeToPython
此代码不使用任何 boost python 或其他 API。不过,Cython 听起来很有趣,如果它可以用于 C++ 方面的简化,它是可以接受的。
【问题讨论】:
-
你有没有想过用 JSON 或 xml 序列化它,然后使用构造函数在 python 中构建对象?
-
不。我的目标是能够共享对象的内存,因此不需要复制。
-
您的 sn-ps 中没有
pFunc对象。它不是那样工作的。myObject必须是一个有效PyObject(我不认为它是 - 在我看到MyObject的定义之前我无法确定)。 “C++ 类已经用 swig 封装”:那么我认为你不应该被要求编写这个 C 代码。 -
感谢 CristiFati,在这个问题中,python 解释器嵌入在 C++ 应用程序中,因此上面的 python 函数是从 C/C++ 调用的。 MyObject 是一个空的“演示”C++ 类,它的内部是无关紧要的。它仅用于正确理解概念,正如标题中所述,概念是“如何将 C++ 对象传递给 Python?”