众所周知,作为解释型语言的 Python 可不是什么超级快速的语言[来源请求],但许多复杂的库函数(比如 NumPy 库)却能执行得相当快速。这主要是因为这些库的核心代码往往是用 C 或者 C++ 写好,并经过了编译,比解释执行的 Python 代码有更快的执行速度。
我们将详细聊一聊如何用 C 或者 C++ 写一个 Python 模组(或软件包),内容主要参考 Python 官方文档。作为范例,我也将用 C 写一个简单的 Python 模组,完成一个简单的数学计算: n!=n×(n-1)×(n-2)… 。为了实现上面的目标,我们需要两个文件:一个 Python 代码 setup.py,以及我们实际编写的 C 语言代码 cmath.c。
总的来说,我们将用 setup.py 把 C 语言写的代码 cmath.c 构建成一个 Python 库(这其中包括编译代码、查找 Python C 库、连接等操作)。
那么,跟随优达学城一起开始吧!
原理
为了让我们的程序/模组能在 Python 代码中被调用执行,模组需要和 Python 解释器 CPython 进行必要的通讯。因此,我们需要 Python.h 头文件里面的若干对象,并用它们构建出合适的结构体。
基本上,我们要做的是把实际的 C 语言方法包装起来,以便能够被 Python 解释器所调用,这样我们的 Python 代码才能够像使用普通的 Python 函数一样,调用这个方法。
编写算法并包装
首先,我们要在 cmath.c 里引入头文件:
#include Python.h
在 Python 头文件里,我们需要用来和 Python 解释器对接的对象(以及函数),都以 Py 开头。在这里,能代表所有 python 对象的 C 对象(基本上就是一个opaque——“不透明”对象)叫做 PyObject。
不过,在实际使用这些对象之前,我们先把求阶乘的算法写出来(注意,0的阶乘是1):
int fastfactorial(int n){
if(n<=1)
return 1;
else
return n * fastfactorial(n-1);
}
接着,我们给这个函数进行一下包装。这个包裹函数接收一个 PyObject 类型的指针(指向今后从 Python 代码传入的参数)作为参数,再返回一个 PyObject 类型的指针(指向上面函数的返回值)给外部。
为此,我们用以下代码来实现这个包裹函数:
static PyObject* factorial(PyObject* self, PyObject* args){
int n;
if (!PyArg_ParseTuple(args,"i