用ctypes包装C++库是一个不好的想法吗?

13
我阅读了以下两个关于封装C库和C++库的讨论帖:wrapping C libraryC++ library,但我还不确定是否理解。 我正在使用的C++库确实使用类和模板,但并没有以过于复杂的方式使用。 用ctypes封装它的问题或注意事项是什么(除了可以在纯python等中这样做之外)?
PyCXX、Cython和boost::python是人们提到的另外三种选择,是否有共识哪一种更适合C ++?
谢谢 奥利弗
2个回答

15
在对ctypes的回答中,我要为boost::python进行辩护:
Boost python提供了一个非常“c ++”的接口,用于连接c ++和Python代码。甚至可以做一些事情,例如允许C ++类的Python子类覆盖虚拟方法。以下是其优点列表:
- 允许Python子类覆盖C++类的虚拟方法。 - 在std::vector<>、std::map<>实例与python列表和字典之间建立桥梁(使用vector_indexing_suite和map_indexing_suite) - 自动共享智能指针(如boost::shared_ptr等)的引用计数与Python引用计数(您还可以将此扩展到任何智能指针)。 - 在从函数传递参数和返回值时具有细粒度的所有权控制。
基本上,如果您有一个设计,想以忠实于语言的方式公开C++接口,那么boost::python可能是最好的方法。
唯一的缺点是增加了编译时间(boost::python广泛使用模板),如果您没有正确地处理事情,有时会出现不透明的错误消息。

4
另一个问题是boost和python版本的强耦合。例如,如果您升级了Python版本,则必须重新构建boost版本。 - user1827356

14
对于C++库能够被Python访问,必须使用C导出名称,这基本上意味着名为foo的函数将在ctypes中作为foo访问。
只有通过export C {}来包含公共接口才能实现这一点,这反过来则不允许函数重载和其中的模板(只有要包装的库的公共接口是相关的,内部工作无关紧要,可以使用任何C++特性)。
原因是C++编译器使用一种称为名称修饰的机制为重载或模板化的符号生成唯一名称。虽然ctypes仍然可以找到函数,只要你知道它的名称已经被编辑,但名称修饰方案依赖于使用的编译器/链接器,并且您不能依赖于它。简而言之:不要使用ctypes来包装在其公共接口中使用C++功能的库。 Cython采用了一种不同的方法。它帮助您构建一个与原始库进行交互的C扩展模块。因此,链接到C++库是通过常规的C++链接机制完成的,从而避免了上述问题。使用Cython的问题在于,每个平台都需要重新编译C扩展库,但是,这同样适用于要包装的C++库。
就个人而言,我认为在大多数情况下,启动Cython的时间是非常值得的,并且最终将比ctypes(对于非常简单的类C接口除外)付出更多。
我没有任何关于boost.python的经验,因此无法对其进行评论(不过,我没有印象它很流行)。

1
感谢提出使用Cython的选项!我选择它来包装C API,并获得了积极的体验 - 它就像在Python中编写少量的C代码,可以提供很多控制。我遇到的一个困难是正确获取构建过程 - 最终我在创建源分发之前预编译了Cython文件。如果有人遇到类似的问题,我在这里详细说明了如何使用Cython包装我的C API,包括构建过程:http://martinsosic.com/development/2016/02/08/wrapping-c-library-as-python-module.html - Martinsos

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