我想从Python应用程序调用C库。我不想包装整个API,只包装与我的案例相关的函数和数据类型。在我看来,我有三个选择:
用c语言创建一个实际的扩展模块,这可能有点过分,而且我还想避免学习编写扩展的开销。
使用Cython将相关部分从C库公开到Python。
在Python中完成所有的事情,使用ctypes与外部库通信。
我不知道2)还是3)哪个更好。3)的优点是ctypes是标准库的一部分,生成的代码将是纯Python——尽管我不确定这个优点到底有多大。
这两种选择有更多的优点/缺点吗?你推荐哪种方法?
编辑:感谢你的回答,它们为任何想做类似事情的人提供了很好的资源。当然,这个决定仍然是针对单一情况做出的——没有一个“这是正确的事情”之类的答案。对于我自己的情况,我可能会使用ctypes,但我也期待在其他一些项目中尝试Cython。
由于没有唯一的正确答案,接受一个答案就有些武断了;我选择了FogleBird的答案,因为它提供了一些关于ctypes的很好的见解,而且它也是目前投票最多的答案。然而,我建议阅读所有的答案,以获得一个良好的概述。
再次感谢。
如果你已经有了一个定义了API的库,我认为ctypes是最好的选择,因为你只需要做一点初始化,然后或多或少地以你习惯的方式调用库。
我认为当你需要新代码时,Cython或用C创建一个扩展模块(这并不难)更有用,例如调用那个库并执行一些复杂、耗时的任务,然后将结果传递给Python。
对于简单的程序,另一种方法是直接执行不同的进程(外部编译),将结果输出到标准输出,并使用subprocess模块调用它。有时这是最简单的方法。
例如,如果你制作一个控制台C程序,或多或少地以这种方式工作
$miCcode 10
Result: 12345678
你可以从Python中调用它
>>> import subprocess
>>> p = subprocess.Popen(['miCcode', '10'], shell=True, stdout=subprocess.PIPE)
>>> std_out, std_err = p.communicate()
>>> print std_out
Result: 12345678
通过一些字符串格式化,您可以以任何您想要的方式获取结果。您还可以捕获标准错误输出,因此非常灵活。
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都很容易安装和开始使用,所以我建议尝试一下它是否适合您的需求。如果它不是你想要的工具,那也不是浪费。
有一个问题让我使用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.