【问题标题】:Exporting C data structures and a C API to Python将 C 数据结构和 C API 导出到 Python
【发布时间】:2011-11-05 23:46:48
【问题描述】:

我有一个带有 C API 的 C 库的源代码。我想将函数和 C 数据结构暴露给 python,以便我可以在我的 python 脚本中使用该库。

有超过 200 多个函数和大约 50 种数据结构,所以如果我可以自动生成 C 和 Python 之间的“胶水”代码会更好。

我目前正在阅读 SWIG,因为它似乎是前进的方向。我应该考虑其他选择(为什么?)。

最后但并非最不重要的一点,(假设 SWIG 是前进的方向),有没有人有一个很好的教程的链接,该教程展示了如何从现有的 C 库编写 Python 扩展模块?

【问题讨论】:

    标签: python c swig


    【解决方案1】:

    我使用 SWIG 2.x 转换了相当复杂的 C 和 C++ API,它为我节省了大量时间。

    SWIG 中的一个重要限制是结构中的结构没有得到很好的处理。这同样适用于 C++ 中的类。我可以完全控制 C/C++ API,因此我事先将我拥有的几个使用内部结构的结构展平并避免了这个问题。

    我的第一个建议是您为 SWIG 定义一个基本模块,该模块仅导入您的头文件,并查看 SWIG 喜欢它的方式。与编译器一样,SWIG 会输出它发现的警告和错误,而这些将是您需要处理的。

    在我让所有功能都工作后,我对结果并不完全满意。 SWIG 从字面上翻译所有函数,但问题是在 C/C++ 中非常常见的一些习语在 Python 中看起来很奇怪。例如,具有指定为指针的输出参数的函数不会很 Pythonic。例如,考虑这个在 C/C++ 中很常见的函数:

    unsigned int getPath(char* buffer, unsigned int size);
    

    这个函数接受一个缓冲区和一个大小,并用一个字符串填充缓冲区,返回实际使用了多少字节,如果出错则返回 0。在 Python 中,必须发送缓冲区(字符串)和大小作为参数会非常奇怪,因此对于这种风格的函数,我添加了可转换为更友好函数的替代版本。在这种情况下,我做了这样的事情:

    const char* getPath();
    

    这个函数的实现只是将一个最大大小的静态缓冲区传递给原始getPath(),并返回静态缓冲区的地址,如果有错误则返回NULL。免责声明:我使用 C++ 编译器,因此我可以定义两个具有不同参数的 getPath() 函数。在 C 中,您需要为每个函数使用不同的名称。 SWIG 自动将 char* 转换为 Python 字符串,因此翻译得非常好。

    除了在 C/C++ 中定义替代函数外,您还可以向 SWIG 提供有关如何转换某些函数及其参数的说明。例如,SWIG 允许您绑定一对缓冲区和大小参数,并将它们视为已翻译函数上的单个字符串参数。像这样的方便翻译还有很多。

    就教程而言,除了官方 SWIG 文档之外,我没有发现任何有用的东西,这非常好,并且有一个特定于 Python 的部分。

    我希望这会有所帮助。

    【讨论】:

    • 感谢您的详细回答。最后,我选择了 Cython,因为我想为 C 库创建一个更 Pythonic 的接口(即编写我自己的包装类)。
    • 其实我现在接受你的回答。在与 Cython 混了几天之后,我的问题在这里没有得到太多帮助——我切换到 SWIG——在 10 分钟内,我编译了我的扩展并准备测试它。当然,SWIG 生成的 python 代码看起来很讨厌,但我可以忍受!
    【解决方案2】:

    我无法对 SWIG 发表评论,但我强烈推荐 Cythontutorialwrapping C libraries)。它确实需要手动编写包装器代码,但至少包装器代码几乎是 Python,而且您可能需要进行一些输入验证/转换和 class 包装,这在很大程度上是 Cython 自动化的。

    另一种选择是 Cython 的前身 Pyrex

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-01-19
      • 2020-04-16
      • 2013-05-06
      相关资源
      最近更新 更多