如何在不构建模块的情况下将C++类公开给Python

Sac*_*cha 5 c++ python swig boost-python

我想知道是否有任何方法可以将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;
     };
Run Code Online (Sandbox Code Playgroud)

我想以某种方式将此类(或其intance)转换为PyObject*,以便将其作为paremter(args)发送到例如PyObject_CallObject:

PyObject* PyObject_CallObject(PyObject* wrapperFunction, PyObject* args)
Run Code Online (Sandbox Code Playgroud)

另一方面,在我的python方面,我将有一个wrapperFunction,它将我的C++类(或其实例)上的指针作为参数获取,并调用其方法或使用其属性:

def wrapper_function(cPlusPlusClass):
    instance = cPlusPlusClass(4, 5)
    result = instance.Addition()
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我并不需要/希望拥有单独的共享库或通过boost python构建模块.我需要的只是找到一种方法将C++代码转换为PyObject并将其发送到python.我无法通过C python库,boost或SWIG找到一种方法.

你有什么主意吗?谢谢你的帮助.

Tan*_*ury 6

据我所知,没有简单的方法来实现这一目标.

要使用C++扩展Python既不是模块也不是中间库,它需要动态加载库,然后导入函数.该方法由ctypes模块使用.要用C++实现同样的目标,需要编写一个ctypes类似于目标编译器的C++ ABI的库.

为了在不引入模块的情况下扩展Python,可以创建一个中间库,它提供了一个包装C++库的C API.然后可以在Python中使用此中间库ctypes.虽然它没有提供确切的调用语法并且确实引入了一个中间库,但它可能比构建一个可以直接与C++接口ctypes类库一样省力.

但是,如果要引入中间库,则可能值得使用Boost.Python,SWIG或其他一些C++/Python语言绑定工具.虽然其中许多工具将通过模块引入扩展,但它们通常提供更清晰的调用约定,更好的绑定过程中的错误检查,并且可能更容易维护.


Sac*_*cha 1

我找到了答案。实际上我正在搜索的内容与这个答案非常相似(感谢 moooeeeep 的评论):

\n\n

\xc2\xa0将 C++ 类实例公开给 python 嵌入式解释器

\n\n

以下 C++ 类(注意!默认构造函数是强制性的):

\n\n
class TwoValues\n{\npublic:\n    TwoValues(void): iValue1(0), iValue2(0) {}\n    TwoValues(int iValue1, int iValue2): iValue1(iValue1_), iValue2(iValue2_) {}\n\n    int Addition(void) const {if (!this) return 0; return iValue1 + iValue2;}\n\npublic:\n    int iValue1;\n    int iValue2;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以通过以下宏来通过 boost 来暴露:

\n\n
BOOST_PYTHON_MODULE(ModuleTestBoost)\n{\nclass_<TwoValues>("TwoValues")\n   .def("Addition",             &TWOVALUES::Addition)\n   .add_property("Value1",      &TWOVALUES::iValue1)\n   .add_property("Value2",      &TWOVALUES::iValue2);\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

另一方面,我定义了一个 python 函数,其中python_script.py获取此类的实例并执行某些操作。例如:

\n\n
def wrapper_function(instance):\n    result = instance.Addition()\n    myfile = open(r"C:\\...\\testboostexample.txt", "w")\n    output = \'First variable is {0}, second variable is {1} and finally the addition is {2}\'.format(instance.Value1, instance.Value2, result)\n    myfile .write(output)\n    myfile .close()\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后在 C++ 端,我可以通过同时发送类的实例来调用此函数,如下所示:

\n\n
Py_Initialize();\n\ntry\n    {\n    TwoValues instance(5, 10);\n    initModuleTestBoost();\n\n    object python_script = import("python_script");\n    object wrapper_function = python_script.attr("wrapper_function");\n    wrapper_function(&instance);\n    }\ncatch (error_already_set)\n    {\n    PyErr_Print();\n    }\n\nPy_Finalize();\n
Run Code Online (Sandbox Code Playgroud)\n\n

优点:

\n\n
    \n
  • 我不需要构建任何共享库或二进制文件
  • \n
  • 当我使用 Boost 时,我不需要担心内存管理和引用计数
  • \n
  • 我不使用共享 boost 指针 (boost::shared_ptr) 来指向我的类的实例
  • \n
\n