我想知道是否有任何方法可以将 C++ 类公开给 Python,但无需构建中间共享库。
这是我理想的场景。例如我有以下 C++ 类:
class toto
{
public:
toto(int iValue1_, int iValue2_): iValue1(iValue1_), iValue2(iValue2_) {}
int Addition(void) const {if (!this) return 0; return iValue1 + iValue2;}
private:
int iValue1;
int iValue2;
};
我想以某种方式将此类(或其实例)转换为 PyObject*,以便将其作为参数(args)发送到例如 PyObject_CallObject:
PyObject* PyObject_CallObject(PyObject* wrapperFunction, PyObject* args)
另一方面,在我的Python端,我将有一个wrapperFunction,它获取我的C++类(或其实例)上的指针作为参数,并调用其方法或使用其属性:
def wrapper_function(cPlusPlusClass):
instance = cPlusPlusClass(4, 5)
result = instance.Addition()
正如你所看到的,我真的不需要/想要有一个单独的共享库或通过 boost python 构建一个模块。我所需要的只是找到一种将 C++ 代码转换为 PyObject 并将其发送到 python 的方法。我找不到通过 C python 库、boost 或 SWIG 来做到这一点的方法。
据我所知,没有简单的方法可以实现这一点。
要在既没有模块也没有中间库的情况下使用 C++ 扩展 Python,需要动态加载库,然后导入函数。这种方法由
ctypes
模块使用。要使用 C++ 完成同样的任务,需要编写一个类似ctypes
的库来理解目标编译器的 C++ ABI。
要在不引入模块的情况下扩展 Python,可以创建一个提供包装 C++ 库的 C API 的中间库。然后可以通过
ctypes
在 Python 中使用这个中间库。虽然它没有提供确切的调用语法并且确实引入了中间库,但它可能比构建一个可以直接与 C++ 交互的ctypes
类库要省力。
但是,如果要引入中间库,则可能值得使用 Boost.Python、SWIG 或其他一些 C++/Python 语言绑定工具。虽然许多这些工具将通过模块引入扩展,但它们通常提供更清晰的调用约定,在绑定过程中更好的错误检查,并且可能更容易维护。
我找到了答案。实际上我正在寻找的内容与这个答案非常相似(感谢 moooeeeep 的评论):
以下 C++ 类(注意!默认构造函数是强制性的):
class TwoValues
{
public:
TwoValues(void): iValue1(0), iValue2(0) {}
TwoValues(int iValue1, int iValue2): iValue1(iValue1_), iValue2(iValue2_) {}
int Addition(void) const {if (!this) return 0; return iValue1 + iValue2;}
public:
int iValue1;
int iValue2;
};
可以通过以下宏来增强曝光:
BOOST_PYTHON_MODULE(ModuleTestBoost)
{
class_<TwoValues>("TwoValues")
.def("Addition", &TWOVALUES::Addition)
.add_property("Value1", &TWOVALUES::iValue1)
.add_property("Value2", &TWOVALUES::iValue2);
};
另一方面,我在
python_script.py
中定义了一个 python 函数,它采用此类的实例并执行某些操作。例如:
def wrapper_function(instance):
result = instance.Addition()
myfile = open(r"C:\...\testboostexample.txt", "w")
output = 'First variable is {0}, second variable is {1} and finally the addition is {2}'.format(instance.Value1, instance.Value2, result)
myfile .write(output)
myfile .close()
然后在 C++ 端,我可以通过同时发送类的实例来调用这个函数,如下所示:
Py_Initialize();
try
{
TwoValues instance(5, 10);
initModuleTestBoost();
object python_script = import("python_script");
object wrapper_function = python_script.attr("wrapper_function");
wrapper_function(&instance);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
优点:
pybind11 提供了
PYBIND11_EMBEDDED_MODULE
,可用于导出 C++ 类,而无需创建扩展模块。