我想从Python应用程序调用C库。我不想包装整个API,只包装与我的案例相关的函数和数据类型。在我看来,我有三个选择:

用c语言创建一个实际的扩展模块,这可能有点过分,而且我还想避免学习编写扩展的开销。 使用Cython将相关部分从C库公开到Python。 在Python中完成所有的事情,使用ctypes与外部库通信。

我不知道2)还是3)哪个更好。3)的优点是ctypes是标准库的一部分,生成的代码将是纯Python——尽管我不确定这个优点到底有多大。

这两种选择有更多的优点/缺点吗?你推荐哪种方法?


编辑:感谢你的回答,它们为任何想做类似事情的人提供了很好的资源。当然,这个决定仍然是针对单一情况做出的——没有一个“这是正确的事情”之类的答案。对于我自己的情况,我可能会使用ctypes,但我也期待在其他一些项目中尝试Cython。

由于没有唯一的正确答案,接受一个答案就有些武断了;我选择了FogleBird的答案,因为它提供了一些关于ctypes的很好的见解,而且它也是目前投票最多的答案。然而,我建议阅读所有的答案,以获得一个良好的概述。

再次感谢。


当前回答

有一个问题让我使用ctypes而不是cython,这在其他答案中没有提到。

Using ctypes the result does not depend on compiler you are using at all. You may write a library using more or less any language which may be compiled to native shared library. It does not matter much, which system, which language and which compiler. Cython, however, is limited by the infrastructure. E.g, if you want to use intel compiler on windows, it is much more tricky to make cython work: you should "explain" compiler to cython, recompile something with this exact compiler, etc. Which significantly limits portability.

其他回答

就我个人而言,我会用C写一个扩展模块。不要被Python C扩展吓倒——它们写起来一点都不难。文档是非常清晰和有用的。当我第一次用Python写一个C扩展时,我想我花了大约一个小时来弄清楚如何写一个——根本没有多少时间。

Cython本身是一个非常酷的工具,非常值得学习,而且惊人地接近Python语法。如果您使用Numpy进行任何科学计算,那么Cython是合适的选择,因为它与Numpy集成以实现快速矩阵运算。

Cython是Python语言的超集。您可以向它抛出任何有效的Python文件,它将吐出一个有效的C程序。在这种情况下,Cython只会将Python调用映射到底层的CPython API。这可能会导致50%的加速,因为您的代码不再被解释。

为了获得一些优化,您必须开始告诉Cython关于代码的其他事实,例如类型声明。如果你告诉它足够多,它可以把代码浓缩成纯c,也就是说,Python中的for循环变成了c中的for循环。在这里,你会看到巨大的速度提升。你也可以在这里链接到外部C程序。

使用Cython代码也非常简单。我觉得手册上说的很难。你只需要做:

$ cython mymodule.pyx
$ gcc [some arguments here] mymodule.c -o mymodule.so

然后你可以在你的Python代码中导入mymodule,完全忘记它可以编译成C语言。

在任何情况下,由于Cython都很容易安装和开始使用,所以我建议尝试一下它是否适合您的需求。如果它不是你想要的工具,那也不是浪费。

要从Python应用程序调用C库,还有cffi,这是ctypes的新替代方案。它为FFI带来了全新的面貌:

它以一种迷人的、干净的方式处理问题(与ctypes相反) 它不需要编写非Python代码(如SWIG, Cython,…)

我再举一个例子:SWIG

它很容易学,做了很多正确的事情,并支持更多的语言,所以花时间学习它是非常有用的。

如果您使用SWIG,您将创建一个新的python扩展模块,但是SWIG将为您完成大部分繁重的工作。

如果您的目标是Windows并选择包装一些专有的c++库,那么您可能很快就会发现msvcrt***.dll (Visual c++ Runtime)的不同版本略有不兼容。

这意味着您可能无法使用Cython,因为产生了包装器。pyd链接到msvcr90.dll (Python 2.7)或msvcr100.dll (Python 3.x)。如果您正在包装的库链接到不同版本的运行时,那么您就不走运了。

然后,为了使事情正常工作,您需要为c++库创建C包装器,将包装器dll链接到与您的c++库相同版本的msvcrt***.dll。然后使用ctypes在运行时动态加载你的手卷包装器dll。

所以有很多小细节,在下面的文章中有详细的描述:

美丽的本地库(Python): http://lucumr.pocoo.org/2013/8/18/beautiful-native-libraries/