Python扩展模块初始化 - 多个文件

6 投票
3 回答
1490 浏览
提问于 2025-04-16 11:53

我创建了一个包含很多源文件和头文件的C库,现在我需要用Python来封装它,这样我就可以“导入”它了。

我已经实现了一个静态方法,可以从Python调用,现在我需要指定这个模块应该向解释器暴露哪些方法。

不过,文档似乎只处理了非常简单的情况,就是只有一个源文件的情况,因为唯一的非静态方法必须是初始化方法,它用来注册其他方法。

据我所知,如果在C中声明的方法是静态的,就无法调用其他源文件中的方法(如果我错了请纠正我),所以每个Python模块只能有一个C文件,因为整个模块中只能有一个非静态方法。

真的是这样吗?如果想从Python访问这些代码,难道就必须把代码结构搞得很糟糕吗?

编辑:

最后我成功的办法是使用Cython。重写C/Python接口只花了大约一个小时(之前因为所有的引用计数规则等花了一整天),而且它还帮你处理所有的构建问题,并且有清晰的文档说明哪些方法可以从Python调用。

特别是,我用到的文档章节有构建说明如何调用C库语言基础如何进行类型转换,特别是指针的转换

对于任何想把现有复杂结构的C代码(也就是不止一个文件的代码)封装成Python库的人,我强烈推荐使用Cython。

3 个回答

0

最后,我成功解决这个问题的方法是使用了 Cython。这不仅让我花了大约一个小时就重写了 C 和 Python 之间的接口(之前因为要处理很多引用计数的规则,花了一整天),而且它还帮我处理了所有的构建问题,并且有清晰的文档,详细说明了哪些方法可以在 Python 中使用。

特别是,我参考的文档章节包括 构建说明如何调用 C 库语言基础,以及 如何进行类型转换,特别是指针的转换

如果你想把现有的复杂 C 代码(也就是不止一个文件的代码)包装成 Python 库,我非常推荐使用 Cython。

2

使用头文件可以让你的外部函数被编译器识别。这不是Python相关的问题,而是C语言中的一个常见特性。

my_prototypes.h:

  // declare the prototype. everybody who includes `my_prototypes.h` now knows that it exists.
  PyObject *func_from_other_module(PyObject *self, PyObject *args);

anotherunit.c:

  PyObject *func_from_other_module(PyObject *self, PyObject *args) {
    // actual implementation
  }

mainunit.c:

  #include "my_prototypes.h"

  static PyMethodDef SpamMethods[] = {

    {"func_from_other_module",  func_from_other_module, METH_VARARGS,
      "Blabla"},
    ...
   {NULL, NULL, 0, NULL}        /* Sentinel */
  }

你说得对,如果一个函数被声明为static,那么它只能在定义它的文件中使用。其实你不需要这样做——只要去掉static就可以了(基本上,你甚至不需要头文件:把函数声明放在mainunit.c的顶部也能正常工作)。

3

其实,模块初始化函数并不是必须是模块中唯一的非静态符号。这更多的是一种最佳实践,目的是为了避免污染C语言在运行时使用的平面命名空间。另一种常见的方法是给所有导出的符号加上特定库的前缀。不过,你可以选择任意一种方法,通常来说,只有静态符号的方法被认为更干净、更稳健。

撰写回答