Python 模块可以用纯 Python 编写,也可以用 C 语言编写。以下展示了如何用 C 扩展 Python。

使用 Python/C API

一个最小的例子

为了说明机制,我们将创建一个最小的扩展模块,其中包含一个函数,该函数输出“Hello”,后跟作为第一个参数传递的名称。

我们首先创建 C 源代码,将其放在 hellomodule.c 中:

C
#include <Python.h>

static PyObject* say_hello(PyObject* self, PyObject* args) {
    const char* name;
    if (!PyArg_ParseTuple(args, "s", &name))
        return NULL;
    printf("Hello %s!\n", name);
    Py_RETURN_NONE;
}

static PyMethodDef HelloMethods[] = {
    {"say_hello", say_hello, METH_VARARGS, "Greet somebody."},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
inithello(void) {
    (void) Py_InitModule("hello", HelloMethods);
}

然后我们需要一个 setup 文件setup.py

Python
from distutils.core import setup, Extension

module1 = Extension('hello', sources = ['hellomodule.c'])

setup (name = 'PackageName',
       version = '1.0',
       description = 'This is a demo package',
       ext_modules = [module1])

然后我们可以使用一个过程来构建模块,其细节取决于操作系统和编译器套件。

使用 GCC for Linux 构建

在我们的模块可以编译之前,如果尚未安装,则必须安装 Python 开发头文件。在 Debian 和基于 Debian 的系统(如 Ubuntu)上,可以使用以下命令安装它们:

Bash
$ sudo apt install python-dev

在 openSUSE 上,所需的包称为 python-devel,可以使用 zypper 安装:

Bash
$ sudo zypper install python-devel

现在 Python.h 可用,我们可以按如下方式编译我们在上一节中创建的模块源代码:

Bash
$ python setup.py build

这将把模块编译成一个名为 hello.so文件,位于 build/lib.linux-i686-x.y 中。

使用 GCC for Microsoft Windows 构建

Microsoft Windows 用户可以使用 MinGW 从命令行编译扩展模块。假设 gcc 在路径中,你可以按如下方式构建扩展:

Bash
python setup.py build -c mingw32

上述命令将生成文件 hello.pyd,这是一个 Python 动态模块似于 DLL。该文件将位于 build\lib.win32-x.y 中。

在 Windows 中构建模块的另一种方法是构建 DLL。(此方法不需要扩展模块文件)。从 cmd.exe,输入:

Bash
gcc -c  hellomodule.c -I/PythonXY/include
gcc -shared hellomodule.o -L/PythonXY/libs -lpythonXY -o hello.dll

其中 XY 代表 Python 的版本,例如 2.4 版本为“24”。

使用 Microsoft Visual C++ 构建

对于 VC8,distutils 损坏了。因此,我们将从命令提示符使用 cl.exe

Bash
cl /LD hellomodule.c /Ic:\Python24\include c:\Python24\libs\python24.lib /link/out:hello.dll

使用扩展模块

更改到 hello.so 文件所在的子目录。在交互式 Python 会话中,你可以按如下方式使用该模块

Python
>>> import hello
>>> hello.say_hello("World")
Hello World!

用于计算斐波那契数的模块

在本节中,我们将介绍一个用于斐波那契数的模块,从而扩展上面的最小示例。与最小示例相比,值得注意的是在 PyArg_ParseTuple()Py_BuildValue() 中使用“i”。

fibmodule.c 中的 C 源代码:

C
#include <Python.h>

int _fib(int n) {
    if (n < 2)
        return n;
    else
        return _fib(n-1) + _fib(n-2);
}

static PyObject* fib(PyObject* self, PyObject* args) {
    int n;
    if (!PyArg_ParseTuple(args, "i", &n))
        return NULL;
    return Py_BuildValue("i", _fib(n));
}

static PyMethodDef FibMethods[] = {
    {"fib", fib, METH_VARARGS, "Calculate the Fibonacci numbers."},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initfib(void) {
    (void) Py_InitModule("fib", FibMethods);
}

构建脚本 (setup.py):

Python
from distutils.core import setup, Extension

module1 = Extension('fib', sources = ['fibmodule.c'])

setup (name = 'PackageName',
       version = '1.0',
       description = 'This is a demo package',
       ext_modules = [module1])

用法:

Python
>>> import fib
>>> fib.fib(10)
55

使用 SWIG

SWIG 是一种工具,它帮助各种脚本和编程语言调用 C 和 C++ 代码。SWIG 使创建 C 语言模块变得更加简单。

要使用 SWIG,你需要先启动并运行它。

你可以像这样在 Ubuntu 系统上安装它:

Bash
$ sudo apt-get install swig
$ sudo apt-get install python-dev

要获取 Windows 版 SWIG,你可以使用 SWIG 下载页面提供的二进制文件

有了 SWIG 之后,你需要创建模块文件模块接口文件

hellomodule.c:

C
#include <stdio.h>

void say_hello(const char* name) {
    printf("Hello %s!\n", name);
}

hello.i:

%module hello
extern void say_hello(const char* name);

然后我们让 SWIG 完成它的工作:

Bash
swig -python hello.i

上述命令生成文件 hello.pyhello_wrap.c

下一步是编译;将 /usr/include/python2.4/ 替换为你的设置中 Python.h 的正确路径:

Bash
gcc -fpic -c hellomodule.c hello_wrap.c -I/usr/include/python2.4/

最后一步,我们进行链接:

Bash
gcc -shared hellomodule.o hello_wrap.o -o _hello.so -lpython

模块的使用方式如下:

Python
>>> import hello
>>> hello.say_hello("World")
Hello World!
Last modified: Friday, 31 January 2025, 1:55 AM