Python:SWIG与ctypes

64 投票
10 回答
27452 浏览
提问于 2025-04-11 09:33

在Python中,什么情况下使用SWIG比ctypes更适合调用共享库中的入口点?假设你还没有SWIG接口文件。

这两者的性能指标是什么?

10 个回答

14

CTypes非常好用,比SWIG简单多了,但它有一个缺点,就是写得不好的或者恶意的Python代码可能会导致Python程序崩溃。你还可以考虑一下boost这个库。在我看来,它比SWIG更简单,同时让你对最终的Python接口有更多的控制。如果你本来就在用C++,那么也不需要再添加其他语言了。

101

我有丰富的使用SWIG的经验。SWIG声称它是一个快速的解决方案,用于包装各种东西。但在实际使用中……


缺点:

SWIG是为了适应所有人和20多种语言而开发的。这通常会导致一些缺点:
- 需要配置(SWIG .i模板),有时候这会很麻烦,
- 对某些特殊情况的处理不足(后面会提到Python属性),
- 对某些语言的性能不足。

Python的缺点:

1) 代码风格不一致。C++和Python的代码风格差别很大(这显而易见),SWIG让目标代码更像Python的可能性非常有限。举个例子,从getter和setter创建属性是非常麻烦的。可以参考这个问答

2) 缺乏广泛的社区支持。SWIG有一些不错的文档。但如果遇到文档中没有的信息,就完全没有帮助。没有博客,也没有搜索能解决问题。所以在这种情况下,只能深入挖掘SWIG生成的代码……这真是太糟糕了,我可以这么说……

优点:

  • 在简单的情况下,使用起来确实快速、简单且直接。

  • 如果你一次生成了SWIG接口文件,就可以把这段C++代码包装成其他20多种语言的代码(!!!)。

  • 关于SWIG的一个大担忧是性能。从2.04版本开始,SWIG引入了'-builtin'标志,使得SWIG比其他自动包装方式更快。至少一些基准测试显示了这一点。


什么时候使用SWIG?

所以我总结了两个适合使用SWIG的情况:

1) 如果需要为多种语言包装C++代码。或者如果将来可能需要为多种语言分发代码。在这种情况下,使用SWIG是可靠的。

2) 如果只需要快速包装几个来自某个C++库的函数供最终使用。


实际经验

更新
自从我们使用SWIG转换我们的库已经过去一年半了。

首先,我们做了Python版本。在使用SWIG的过程中确实遇到了一些麻烦。但现在我们已经将库扩展到了Java和.NET。所以我们用1个SWIG支持了3种语言。我可以说,SWIG真是太棒了,节省了大量时间。

更新2
我们已经使用SWIG两年了。SWIG已经集成到我们的构建系统中。最近,我们的C++库进行了重大API更改。SWIG工作得非常完美。我们只需要在.i文件中添加几个%rename,这样我们的CppCamelStyleFunctions()在Python中就变得looks_more_pythonish了。起初我担心可能会出现一些问题,但结果一切顺利。这真是太神奇了。只需几处编辑,所有内容就可以在3种语言中分发。现在我很有信心,使用SWIG是我们这个案例的好选择。

更新3
我们已经使用SWIG超过3年了。重大变化:Python部分完全用纯Python重写。原因是现在大多数应用都使用我们的库的Python版本。即使纯Python版本的速度比C++包装慢,但对用户来说,使用纯Python更方便,而不是与本地库打交道。

SWIG仍然用于.NET和Java版本。

这里的主要问题是“如果我们从头开始这个项目,还会使用SWIG吗?”答案是肯定的!SWIG让我们能够快速将产品分发到多种语言。这段时间的使用让我们更好地理解了用户的需求。

71

SWIG 是一个工具,它可以生成 C 或 C++ 代码,虽然生成的代码看起来不太好。对于简单的函数(那些可以直接翻译的),使用起来很简单;对于更复杂的函数(比如有输出参数的函数,需要额外的步骤才能在 Python 中表示),使用起来也算比较容易。不过,如果你想要更强大的接口,通常需要在接口文件中写一些 C 代码。除了简单的使用场景外,你还需要了解 CPython 是如何表示对象的——这并不难,但要记住这一点。

ctypes 允许你直接访问 C 的函数、结构和其他数据,还可以加载任意的共享库。使用 ctypes 不需要写任何 C 代码,但你需要理解 C 是怎么工作的。可以说,ctypes 和 SWIG 是两种不同的方式:ctypes 不会生成代码,也不需要在运行时使用编译器,但如果你想做的不只是简单的操作,你需要了解 C 的数据类型、类型转换、内存管理和对齐等知识。你还需要手动或自动将 C 的结构体、联合体和数组转换成相应的 ctypes 数据结构,并确保内存布局正确。

在执行速度上,SWIG 可能比 ctypes 更快,因为 SWIG 在编译时就处理了大部分管理工作,而不是在 Python 运行时处理。不过,除非你需要频繁调用很多不同的 C 函数,否则这种开销通常不会太明显。

在开发时间上,ctypes 的启动成本要低得多:你不需要学习接口文件的知识,也不需要生成 .c 文件并编译它们,更不需要处理警告。你可以很轻松地开始使用一个 C 函数,然后逐步扩展。你还可以直接在 Python 解释器中测试和尝试各种东西。虽然将大量代码封装起来有点繁琐,但也有一些工具试图简化这个过程(比如 ctypes-configure)。

而 SWIG 则可以用来为多种语言生成封装代码(当然,还是有一些特定语言的细节需要处理,比如我之前提到的自定义 C 代码)。当需要封装大量代码时,SWIG 可以轻松处理这些情况,生成的代码设置起来也比 ctypes 更简单。

撰写回答