Python:SWIG与ctypes
在python中,在哪种情况下,SWIG是比ctypes更好的选择,用于在共享库中调用入口点?假设我们还没有SWIG接口文件。
两者的性能指标是什么?
解决方案
CTypes非常酷,比SWIG容易得多,但是它的缺点是编写不当或者恶意编写的python代码实际上会使python进程崩溃。我们还应该考虑使用boost python。恕我直言,它实际上比Swig更容易,同时使我们可以更好地控制最终的python接口。如果仍在使用C ++,则也不会在混合中添加任何其他语言。
SWIG生成(相当难看)C或者C ++代码。对于简单的函数(可以直接翻译的事物),它很简单;对于更复杂的函数(例如,具有输出参数的函数,需要用额外的翻译步骤来用Python表示),它相当容易使用。需要将C的位写为接口文件的一部分。对于除简单使用之外的任何内容,我们都需要了解CPython及其如何表示对象-不难,但要记住一些事情。
ctypes允许我们直接访问C函数,结构和其他数据,并加载任意共享库。我们不需要为此编写任何C,但是我们确实需要了解C的工作原理。我们可能会争辩说,它是SWIG的另一面:它不会生成代码,并且不需要在运行时进行编译器,但是对于简单使用而言,它确实需要我们了解C数据类型,转换,内存管理和对齐工作。我们还需要手动或者自动将C结构,联合和数组转换为等效的ctypes数据结构,包括正确的内存布局。
在纯执行中,SWIG可能比ctypes更快-因为围绕实际工作的管理是在C时在编译时完成的,而不是在Python时运行的。但是,除非我们接口许多不同的C函数,但每次仅接口几次,否则开销实际上不会很明显。
在开发期间,ctypes的启动成本要低得多:我们不必了解接口文件,不必生成.c文件并进行编译,也不必检出和静默警告。我们只需花很少的精力就可以开始使用单个C函数,然后将其扩展为更多功能。我们可以直接在Python解释器中进行测试并尝试尝试。包装许多代码有些乏味,尽管有人尝试使之简化(例如ctypes-configure)。
另一方面,SWIG可用于为多种语言生成包装器(除非需要填写特定于语言的详细信息,例如我上面提到的自定义C代码。)当包装大量SWIG可以用很少的代码处理的代码时帮助,代码生成也可以比等效的ctypes容易得多。
我们还可以使用Pyrex,它可以充当高级Python代码和低级C代码之间的粘合剂。例如,lxml是用Pyrex编写的。
ctypes很棒,但是不能处理C ++类。我还发现ctypes比直接C绑定慢大约10%,但这在很大程度上取决于我们所调用的内容。
如果要使用ctype,请一定要查看Pyglet和Pyopengl项目,这些项目包含大量ctype绑定示例。
我会提出相反的建议,如果可以的话,建议我们使用标准Python API编写扩展库。从C和Python角度来看,它确实集成得很好……如果我们有使用Perl API的经验,我们会发现这是一个非常令人惊喜的惊喜。
Ctypes也很不错,但是正如其他人所说的,它不支持C ++。
我们要包装的图书馆有多大?代码库更改速度有多快?还有其他维护问题吗?这些都可能会影响对编写Python绑定的最佳方式的选择。
以我的经验,ctypes确实有一个很大的劣势:当出现问题时(对于任何复杂的接口它总是会发生错误),调试起来实在是很麻烦。
问题在于,ctypes / ffi魔术掩盖了堆栈的很大一部分,并且没有简单的方法来确定如何到达特定点以及为什么参数值就是它们。