前言(更新:更方便易用的方式在http://www.swig.org/tutorial.html)
需要扩展Python语言的理由:
创建Python扩展的步骤
1. 创建应用程序代码
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 10
int fac(int n) {
if (n < 2)
return 1;
return n * fac(n - 1);
}
char *reverse(char *s) {
register char t;
char *p = s;
char *q = (s + (strlen(s) - 1));
while (p < q) {
t = *p;
*p++ = *q;
*q-- = t;
}
return s;
}
int main() {
char s[BUFSIZE];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", reverse(s));
return 0;
}
2. 利用样板来包装代码
a. 包含python的头文件
b. 为每个模块的每一个函数增加一个型如PyObject* Module_func()的包装函数
int res;//计算结果值
int num;//参数
PyObject* retval;//返回值
//i表示需要传递进来的参数类型为整型,如果是,就赋值给num,如果不是,返回NULL;
res = PyArg_ParseTuple(args, "i", &num);
if (!res) {
//包装函数返回NULL,就会在Python调用中产生一个TypeError的异常
return NULL;
}
res = fac(num);
//需要把c中计算的结果转成python对象,i代表整数对象类型。
retval = (PyObject *)Py_BuildValue("i", res);
return retval;
}
int m;
if (!(PyArg_ParseTuple(args, "i", &num))) {
return NULL;
}
return (PyObject *)Py_BuildValue("i", fac(num));
}
Extest_reverse(PyObject *self, PyObject *args) {
char *orignal;
if (!(PyArg_ParseTuple(args, "s", &orignal))) {
return NULL;
}
return (PyObject *)Py_BuildValue("s", reverse(orignal));
}
Extest_doppel(PyObject *self, PyObject *args) {
char *orignal;
if (!(PyArg_ParseTuple(args, "s", &orignal))) {
return NULL;
}
//ss,就可以返回两个字符串,应该reverse是在原字符串上进行操作,所以需要先strdup复制一下
return (PyObject *)Py_BuildValue("ss", orignal, reverse(strdup(orignal)));
}
Extest_doppel(PyObject *self, PyObject *args) {
char *orignal;
char *reversed;
PyObject * retval;
if (!(PyArg_ParseTuple(args, "s", &orignal))) {
return NULL;
}
retval = (PyObject *)Py_BuildValue("ss", orignal, reversed=reverse(strdup(orignal)));
free(reversed);
return retval;
}
c. 为每个模块增加一个型如PyMethodDef ModuleMethods[]的数组
ExtestMethods[] = {
{"fac", Extest_fac, METH_VARARGS},
{"doppel", Extest_doppel, METH_VARARGS},
{"reverse", Extest_reverse, METH_VARARGS},
{NULL, NULL},
};
d. 增加模块初始化函数void initMethod()
Py_InitModule("Extest", ExtestMethods);
}
#include <stdlib.h>
#include <string.h>
#include "Python.h"
#define BUFSIZE 10
int fac(int n) {
if (n < 2)
return 1;
return n * fac(n - 1);
}
char *reverse(char *s) {
register char t;
char *p = s;
char *q = (s + (strlen(s) - 1));
while (p < q) {
t = *p;
*p++ = *q;
*q-- = t;
}
return s;
}
static PyObject *
Extest_fac(PyObject *self, PyObject *args) {
int res;
int num;
PyObject* retval;
res = PyArg_ParseTuple(args, "i", &num);
if (!res) {
return NULL;
}
res = fac(num);
retval = (PyObject *)Py_BuildValue("i", res);
return retval;
}
static PyObject *
Extest_reverse(PyObject *self, PyObject *args) {
char *orignal;
if (!(PyArg_ParseTuple(args, "s", &orignal))) {
return NULL;
}
return (PyObject *)Py_BuildValue("s", reverse(orignal));
}
static PyObject *
Extest_doppel(PyObject *self, PyObject *args) {
char *orignal;
char *resv;
PyObject *retval;
if (!(PyArg_ParseTuple(args, "s", &orignal))) {
return NULL;
}
retval = (PyObject *)Py_BuildValue("ss", orignal, resv=reverse(strdup(orignal)));
free(resv);
return retval;
}
static PyMethodDef
ExtestMethods[] = {
{"fac", Extest_fac, METH_VARARGS},
{"doppel", Extest_doppel, METH_VARARGS},
{"reverse", Extest_reverse, METH_VARARGS},
{NULL, NULL},
};
void initExtest() {
Py_InitModule("Extest", ExtestMethods);
}
int main() {
char s[BUFSIZE];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", reverse(s));
test();
return 0;
}
3. 编译与测试
a. 创建setup.py
from distutils.core import setup, Extension
MOD = 'Extest'
setup(name=MOD, ext_modules=[Extension(MOD, sources=['Extest.c'])])
b. 通过运行setup.py来编译和连接你的代码
c. 进行调试
from ctypes import *
import os
#需要使用绝对路径
extest = cdll.LoadLibrary(os.getcwd() + '/Extest.so')
print extest.fac(4)
Extest_test(PyObject *self, PyObject *args) {
test();
#返回空的话,就使用下面这一句
return (PyObject *)Py_BuildValue("");
}
简单性能比较
import time
start = time.time()
a = Extest.reverse("abcd")
timeC = time.time() - start
print 'C costs', timeC, 'the result is', a
start = time.time()
b = list("abcd")
b.reverse()
b = ''.join(b)
timePython = time.time()-start
print 'Python costs', timePython, 'the result is', b