分类: Python/Ruby
2011-02-24 23:58:16
1. 直接C扩展Python的方法
Python的扩展API是主要为C语言提供的,可以利用该API为要导出的C函数建立包装器(wrapper)。包装器用来处理Python对象与底层C函数中的变量与所需值之间的转换,并将C函数注册到Python的自定义module中。
假设将要导出的函数成为模块函数,对应wrapper中的函数为包装函数。则wrapper文件主要包含以下几个部分:
Ø include "Python.h";
Ø 每个模块函数的包装函数,即:PyObject* Module_func();
Ø 每个模块函数的函数定义,即:PyMethodDef ModuleMethods[]对应表;
Ø 模块的初始化函数:void initModule()部分。
简单示例程序:
假设有以下C文件example.c:
--------------------------------------------------------------------------------
/**************** example.c ******************/
double My_variable = 3.0;
int fact(int n)
{
if (n <= 1)
return 1;
else
return n*fact(n-1);
}
int my_mod(int n, int m)
{
return (n % m);
}
--------------------------------------------------------------------------------
我们要导出其中的两个函数fact()和my_mod(),则要为之写wrapper。文件内容如下:
--------------------------------------------------------------------------------
/************* example_wrap.c ***************/
#include
extern int fact(int);
extern int my_mod(int, int);
PyObject *fact_wrap(PyObject *self, PyObject *args)
{
int num;
if (!PyArg_ParseTuple(args, "i", &num))
return NULL;
return Py_BuildValue("i", fact(num));
}
PyObject *my_mod_wrap(PyObject *self, PyObject *args)
{
int n, m;
if (!PyArg_ParseTuple(args, "ii", &n, &m))
return NULL;
return Py_BuildValue("i", my_mod(n, m));
}
static PyMethodDef example2methods[] = {
{"fact", fact_wrap, METH_VARARGS, "compute fact of a number"},
{"my_mod", my_mod_wrap, METH_VARARGS, "compute the mod of two numbers"},
{NULL, NULL},
};
void initexample2(void)
{
Py_InitModule("example2", example2methods);
}
--------------------------------------------------------------------------------
编译连接使用以下命令:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ gcc -fpic -c -I/usr/include/python2.2 -
I/usr/lib/python2.2/config example.c example_wrap2.c
[piaoah@RUDDY example]$ gcc -shared -o example2.so example.o example_wrap2.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------
则生成共享库文件example2.so。我们可以在Python环境中导入example2模块,并使用其中的函数:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ python
Python 2.3.2 (#5, Mar 24 2004, 10:17:17)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import example2
>>> example2.fact(5)
120
>>> example2.fact(1)
1
>>> example2.fact(3)
6
>>> example2.fact(6)
720
>>> example2.my_mod(1,3)
1
>>>
--------------------------------------------------------------------------------
2. 怎样用SWIG生成C的wraper
SWIG是一个自动的扩展构造工具。它读入注释的源程序头文件(后缀为.i的脚本文件),为python、tcl、perl等多种脚本语言产生wrap代码。
步骤大致为:
(1) 写源程序;
(2) 写后缀为.i的脚本文件;
(3) 使用命令"swig -python example.i"生成example_wrap.c,example_wrap.doc;
(4) 编译连接成共享库。
.i脚本文件的格式很简单,只需要列出要导出的函数或类型,并注释必要信息。还以上面的example.c为例,写example.i脚本文件如下:
--------------------------------------------------------------------------------
/**************** example.i ******************/
%module example
%{
#include "example.h"
%}
extern double My_variable;
extern int fact(int);
extern int my_mod(int n, int m);
--------------------------------------------------------------------------------
在命令行输入以下命令"swig -python example.i",会在当前目录下生成example_wrap.c,example_wrap.doc两个文件。前者即为example.c的wrap文件,后者为解释文件。
接下来使用编译连接命令生成example.so文件。命令同第一节:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ gcc -fpic -c -I/usr/include/python2.2
-I/usr/lib/python2.2/config example.c example_wrap2.c
[piaoah@RUDDY example]$ gcc -shared -o example2.so example.o example_wrap2.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------
接下来就可以在Python环境中使用example模块中的函数了。
3. 用SWIG生成C++的wraper
用SWIG生成C++的wrapper过程类似于C wrapper。它的步骤如下:
(1) 写.cpp源程序;
(2) 写.i脚本文件;
(3) swig -c++ -python foo.i
生成foo_wrap.c,foo_wrap.doc;
(4) 编译连接成共享库foo.so。
则生成Python的foo模块,可以通过调入foo模块使用其中的类成员函数、成员变量。
一个简单示例:
假设有如下C++源程序:
--------------------------------------------------------------------------------
/**************** number.h ******************/
class Number
{
public:
Number(int start);
~Number();
void add(int value);
void sub(int value);
void display();
int data;
};
--------------------------------------------------------------------------------
对应实现的cpp文件如下:
--------------------------------------------------------------------------------
/***************** number.cpp ****************/
#include "number.h"
#include
Number::Number(int start)
{
data = start;
printf("Number: %d\n", data);
}
Number::~Number()
{
printf("~Number: %d\n", data);
}
void Number::add(int value)
{
data += value;
printf("add %d\n", value);
}
void Number::sub(int value)
{
data -= value;
printf("sub %d\n", value);
}
void Number::display()
{
printf("Number = %d\n", data);
}
--------------------------------------------------------------------------------
为之写number.i文件:
--------------------------------------------------------------------------------
%module Number
%{
#include "number.h"
%}
class Number {
public:
Number(int start);
~Number();
void add(int value);
void sub(int value);
void display();
int data;
};
--------------------------------------------------------------------------------
使用命令:"swig -c++ -python number.i",得到number_wrap.c,number_wrap.doc(有些系统生成的是number.py)两个文件。
再使用命令:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ g++ -fpic -c -I/usr/include/python2.2 -
I/usr/lib/python2.2/config number.cpp number_wrap.c
[piaoah@RUDDY example]$ g++ -shared -o number.so number.o number_wrap.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------
生成number.so文件,可以在Python环境中使用Number类及其成员函数。但类名和成员函数名稍有变化,具体可见生成的number_wrap.doc(或number.py)文件。
接下来便可以在python环境中导入number模块了:
--------------------------------------------------------------------------------
[piaoah@RUDDY NUMBER]$ python
Python 2.3.2 (#5, Mar 24 2004, 10:17:17)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import number
>>> mynum = Number.new_Number(5)
Number: 5
>>> Number.Number_display(mynum)
Number = 5
>>> Number.Number_add(mynum, 1)
add 1
>>> Number.Number_display(mynum)
Number = 6
>>> Number.Number_sub(mynum, 3)
sub 3
>>> Number.Number_display(mynum)
Number = 3
>>> Number.delete_Number(mynum)
~Number: 3
>>>
--------------------------------------------------------------------------------