18

我正在考虑在我的程序中使用 python (CPython) 来允许在我的环境中编写用户脚本,并允许我使用 pyside,c++ 的 qt 绑定来为我的应用程序创建 GUI。这些可以有效地与 GUI python 代码稍后可以编译掉以提高速度(如果可能的话)的想法分开。

我对 python 非常陌生,我真的在寻找最有效的方法来生成可靠的绑定,并且需要维护的附加代码绝对最少,因为绑定可能会随着项目的发展而经常变化。我需要它以便 python 类扩展具有虚拟的 c++ 类。

我已经研究过 PyBindGen,它经常卡在我的库中的东西上,以至于它实际上没有用。

您在这方面推荐的任何帮助/建议/链接/工作流程都会非常有帮助。

4

6 回答 6

16

我知道只有两个项目有 C++ 的自动绑定生成器。第一个是 SWIG。正如其他一些答案已经说过的那样,它有点过时,但它确实有效。第二个是 Boost.Python - 它本身不会自动生成绑定,但您可以使用Boost.Pyste为您完成。它需要 GCC-XML 来解析您的原始源代码并编写 Boost.Python 绑定。这两个选项都支持可以从 Python 重载的 C++ 中的虚拟方法。

也就是说,我必须补充一点,通常,当您绑定时,您不会盲目地将 C++ 中的所有内容绑定到 Python 中——如果您这样做,您不会从 Python 方面获得非常 Python 的感觉。相反,您以最 Pythonic 的方式设计您希望如何在 Python 中使用您的库,然后您回过头来看看如何使用可能的绑定库之一将其修补到您的 C++ 代码中。例如std::vector,您希望您的库调用处理 Python 列表或可迭代对象,而不是处理 's。如果您的 C++ 库收到一个std::map,您希望使用 Python 字典来处理它。如果它是一个数组,也许 anumpy.ndarray会更方便。等等...

也就是说,您仍然可以设计绑定,以便最大限度地减少维护。

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

  1. SWIG - 如您所知
  2. Boost.Python - 这是我们通常在这里使用的 - 结构很好
  3. Cython - 非常接近 Python 的简洁语法 - 他们声称比 Boost.Python 快得多
  4. SIP - 不是很传播,但它就在那里
  5. pybind11 - 类似于 Boost.Python 的语法,得益于 C++11 的紧凑实现。

这些现在处于非活动状态:

  1. PyBindGen - 声称是最快的,但自 2017 年 5 月 21 日起处于非活动状态,2014 年的上一个版本 - 目前在 github 上维护(https://github.com/gjcarneiro/pybindgen/releases
  2. ECS:Python -自 2014 年 12 月 6 日 (v2.8) 起处于非活动状态,已移至 github ( https://github.com/MarcusTomlinson/ECS-Python )
  3. PyCXX - 使编写 Python 扩展更容易的 C++ 工具 -不活动?最后一个版本是 2017 年 4 月 23 日的 v7.0.2
  4. CLIF - CLIF 为为各种语言创建 C++ 包装器生成器提供了一个通用基础 -不活动?回购活动不多(只有 14 次提交)

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

  1. ctypes - 这是 Python 原生的,不需要安装外部模块。
  2. cffi - 这是一个新包,灵感来自 Lua JIT 上的等效设计。
于 2013-08-05T07:54:01.507 回答
2

如果您正在寻找速度,我也肯定会投票给 Cython。据我所知,C++ 与 Python 的其他接口方式,与其他绑定工具相比,Cython 的维护/更新并没有那么繁重,就“工作流的流畅性”增益而言。(Cythonized 代码认为它和纯 C 一样快,或者离那不远,这也使它非常有趣)。

无论如何,有几个很好的 API 用于将 python 代码与 C++ 连接(Boost.Python,...),但我认为所有这些都将导致需要直接在 C++ 源代码中公开方法(你们告诉我,如果我'错了,或不精确)。

另一方面,Cython 将使您可以将您的 C++ API(GUI 或其他...)与暴露源(所谓的 .pyx 扩展名)严格分开。最终的工作流程是:

C++ API => 编译为共享对象 => Cython 扩展(导入和公开 C++ 功能)=> 扩展编译 => 使用扩展(要添加到 python 路径的扩展)。

好消息是,您只需要维护与不断发展的 C++ 特性相关的 .pyx 文件池中的变化部分(其中包括需要公开的特性)。一开始这是一种投资,但根据我的经验,一旦设置了这个工作流程,让整个东西变得复杂起来就很简单了。

现在关于您需要扩展具有虚拟的类并从 Python 覆盖它们(如果我理解正确的话)。这是可行的。再一次,不是那么直接,但你应该看看这个线程

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

Hummf,现在我正在回读自己,看起来有点混乱。希望这仍然有帮助。

如果您选择 Cython 选项,我可以更具体地说明您必须处理的工作流程,如果您要求我这样做,但我认为上面链接的线程是一个很好的起点......

于 2012-12-25T04:19:15.123 回答
2

对于现代 C++,请使用 CLIF ( https://github.com/google/clif )。它不会发现你的 API,你需要用 Python 术语来描述它。

CLIF 将使用最新的 LLVM/Clang 编译器重新编译您的头文件,并为 Python 扩展模块生成 C++ 源代码。

它可以理解复杂的数据结构:def f() -> dict<str, set<int>>.

于 2017-08-04T04:04:31.253 回答
2

对于现代 C++,使用 cppyy:http ://cppyy.readthedocs.io/en/latest/

它基于 Cling,Clang/LLVM 的 C++ 解释器。绑定是在运行时进行的,不需要额外的中间语言。感谢 Clang,它支持 C++17。

具体到使用 Qt 的原始问题:最近的几个更新明确地支持所有 KDE 的绑定生成。

为了速度:PyPy 原生支持 cppyy。

注意:我是cppyy的主要作者。

于 2018-03-06T18:30:34.723 回答
0

AFAICT,C++ 没有那么多选择。较早的项目之一是SWIG;据报道它有点神秘和笨重,但由于它已经存在了很长时间,它也应该涵盖很多其他项目没有处理的东西。您可能还想看看Cython

于 2012-12-21T12:40:53.267 回答
0

SWIG 是一个很棒的工具,可以做你想做的事

http://sourceforge.net/projects/swig/

于 2013-08-05T08:10:48.427 回答