生成Python绑定,需要使用哪些方法/程序?

18

我计划在我的程序中使用Python(CPython),既可以允许用户在我的环境中编写脚本,也可以让我使用Pyside(C++的Qt绑定)来创建应用程序的GUI界面。这两部分可以有效地分离开来,即如果可能的话,GUI Python代码稍后可以编译以提高速度。

我对Python非常陌生,因此我真的在寻找生成坚实绑定的最有效方法,并且添加的代码最少,以便在项目发展过程中维护绑定时能够尽量减少更改。我需要的是Python类扩展具有虚拟函数的C++类。

我已经研究了PyBindGen,但它经常在库中出现问题,不太实用。

如果您在这方面有任何帮助、建议、链接或工作流程推荐,将非常有帮助。


1
在我看来,如果你将它们集成到那个层次,你的Python和C++部分很可能会非常交织在一起。但是我总体上支持寻找良好的绑定方法。+1。 - Prof. Falken
6个回答

16

目前我知道只有几个C++自动绑定生成器项目。第一个是SWIG。正如其他答案已经提到的,它有点老式,但它还可以使用。第二个是Boost.Python-本身不会自动生成绑定,但你可以使用Boost.Pyste来为你生成。它需要GCC-XML解析原始源代码并编写Boost.Python绑定。在这个领域的新进入者是cppyyShiboken。所有选项都支持可以从Python重载的C++虚拟方法。

话虽如此,我必须补充说,在绑定时,应该避免盲目地将C++中的所有内容绑定到Python中-如果您这样做,您可能无法从Python端获得非常“Pythonic”的感觉。相反,您应该以最具Python风格的方式设计您希望在Python中使用的库,然后回头看看如何使用其中一种可能的绑定库将其patch到您的C++代码上。例如,您可以选择处理Python列表或可迭代对象,而不是处理std :: vector。如果您的C++库接收到std :: map,则希望使用Python字典进行处理。如果是数组,则可能更方便使用numpy.ndarray。等等...

话虽如此,您仍然可以设计您的绑定,以使您的维护最小化。

以下是其他Python / C ++封装的列表,以防您决定进一步查看:

  1. SWIG - 正如您已经了解的那样
  2. Boost.Python - 我们通常在此处使用的库-非常好结构化。 pybind11可能是一个更现代的替代品。
  3. Cython - 语法非常接近Python-他们声称比Boost.Python快得多。
  4. SIP - 没有太广泛的应用,但确实存在。
  5. pybind11 - 语法类似于Boost.Python,由于C++11的紧凑实现。
  6. cppyy - cppyy利用Cling C++解释器和LLVM提供完全自动化、动态Python-C++绑定。通过C++17(和部分C++20)支持PyPy(本地)、CPython和C++语言标准。
  7. Shiboken - 是Qt框架的一部分,可以从C或C ++头文件中提取信息并生成允许将C或C ++项目带入Python的CPython代码。

这些现在已停用:

  1. PyBindGen - 声称是最快的,但自2017年5月21日以来处于停用状态,上一个版本发布于2014年-当前在github上维护(https://github.com/gjcarneiro/pybindgen/releases
  2. ECS:Python - 自2014年12月6日(版本2.8)以来处于不活跃状态,已迁移到github (https://github.com/MarcusTomlinson/ECS-Python)
  3. PyCXX - C++的工具,使得编写Python扩展更加容易 - 不活跃? 上一个版本是2017年4月23日的v7.0.2
  4. CLIF - CLIF为为各种语言创建C ++包装器生成器提供了通用基础 - 不活跃? 仓库上没有太多活动(只有14个提交)

为了完整起见,还可以直接将编译后的C代码加载到Python中,而不需要创建正式的绑定。您可以使用以下两个Python模块之一与FFI一起做到这一点:

  1. ctypes - 这是原生的Python,无需安装外部模块。
  2. cffi - 这是一个新的包,灵感来自于Lua JIT上的等效设计。

3
这个列表的新成员是pybind11(https://github.com/wjakob/pybind11,http://pybind11.readthedocs.org/en/latest/)。免责声明:我是作者。 - Wenzel Jakob
@WenzelJakob 我认为你应该添加一个新的答案,包括那些信息,并在帖子正文中加入免责声明。 - Bill Woodger
Andre,如果您想考虑添加Wenzel Jakob建议的信息,请这样做(此答案的第4个修订版)。 - Bill Woodger
请翻译,显然我没有足够的声望... - André Anjos
在这里...我不确定如何进行更改,所以有些混乱。现在已经完成了。感谢你的光临! - André Anjos
显示剩余3条评论

2
如果您正在寻找速度,我肯定会投票给Cython。就我所知,与Python集成C++的其他方式相比,Cython在维护/更新方面不那么繁重,关于“工作流程的流畅性”方面也是如此。(Cython化的代码声称与纯C一样快,或者离那也不远,这也使它非常有趣)。
无论如何,有几个很好的API可以将Python代码与C++连接起来(Boost.Python等),但我认为所有这些都将导致需要直接在C++源代码中公开方法(如果我错误或不准确,请告诉我)。
另一方面,Cython将为您提供保持C++ API(GUI或其他内容)严格分离于暴露源(所谓的.pyx扩展名)的可能性。最终的工作流程将是:
C++ API => 编译为共享对象 => Cython扩展(导入和公开C++功能)=> 扩展的编译 => 使用扩展(将扩展添加到您的Python路径)。
好消息是,您只需要维护与正在发展的 C++ 特性相关的 .pyx 文件的变化部分。这在一开始可能需要一些投入,但根据我的经验,一旦设置了这种工作流程,就很容易使整个复杂度增加。

现在关于您需要扩展具有虚函数并从 Python 中覆盖它们的类(如果我理解正确)。这是可行的。再说一遍,不太直接,但您应该查看这个 thread

坏消息:在这种特殊情况下,您将不得不创建一些额外的 C++ 适配器/接口,以便在扩展的 python 方法没有覆盖给定的父方法时调用父方法。(请注意,重新定义一个从 python 重写的 C++ 公开方法,无论是否为虚函数,都是对函数的替换,但绝对不等同于覆盖)。

嗯,现在我自己再读一遍,看起来有点混乱。希望这仍然有帮助。

如果您选择使用Cython选项,我可以更详细地介绍您将要处理的工作流程,但如果您请求,我认为上面链接的主题已经是一个很好的起点...

如果您需要有关使用Cython封装C/C++库的更多详细信息,您可能会发现我写的一篇文章很有用 - 它包含了封装和分发C/C++库所需的所有细节:http://martinsosic.com/development/2016/02/08/wrapping-c-library-as-python-module.html - Martinsos

2
对于现代C++,请使用cppyy:http://cppyy.readthedocs.io/en/latest/。它基于Cling,是Clang / LLVM的C ++解释器。绑定是在运行时完成的,不需要额外的中间语言。由于使用了Clang,所以支持C++17。
针对原始问题使用Qt的情况:最近进行了几次更新,专门支持生成所有KDE的绑定。
为了提高速度:cppyy可以被PyPy本地支持。
注意:我是cppyy的主要作者。

cppyy 可以轻松地与基于 Qt 的项目一起使用吗? - Denis Rouzaud
是的,可以使用为KDE设计的cmake片段:http://cppyy.readthedocs.io/en/latest/bindings_generation.html#cmake-interface - Wim Lavrijsen

2
对于现代C++,使用CLIF(https://github.com/google/clif)。 它不会自动发现您的API,您需要用Python语言来描述它。
CLIF将使用最新的LLVM/Clang编译器重新编译您的头文件,并为Python扩展模块生成C++源代码。
它可以理解复杂的数据结构:def f() -> dict<str, set<int>>

0
据我所知,C++ 的选择并不是很多。其中一个较早的项目是 SWIG;据报道它有点古怪和笨重,但由于它已经存在了很长时间,应该也涵盖了其他项目未处理的许多内容。你可能还想看看 Cython

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接