开发者社区> 嗯哼9925> 正文

使用C语言扩展Python(一)

简介:
+关注继续查看
开发环境:Ubuntu9.10,python2.6,gcc4.4.1

1,ubuntu下的python运行包和开发包是分开的,因此需要在新利得里面安装python-all-dev,从而可以在代码中引用python的头文件和库。

2.下面是一个最简单的可以供python调用的c扩展模块,假设c程序文件名为foo.c:

复制代码
代码
#include <Python.h>

static PyObject* foo_bar(PyObject* self, PyObject* args) {
    Py_RETURN_NONE;
}

static PyMethodDef foo_methods[] = {
    {"bar",(PyCFunction)foo_bar,METH_NOARGS,NULL},
    {NULL,NULL,0,NULL}
};

PyMODINIT_FUNC initfoo() {
    Py_InitModule3("foo", foo_methods, "My first extension module.");
复制代码
     我们可以将上述模块分成3个部分:1)c模块想对外暴露的接口函数。2)提供给外部的python程序使用的一个c模块函数名称映射表。3)c模块的初始化函数。模块的第一行将Python.h引入到模块中,这个文件将使得你的模块可以hook进python的解释器,从而可以为外部的python程序所使用。

c模块中的函数签名一般有下列三种形式:

PyObject* MyFunction(PyObject* self, PyObject* args);
PyObject* MyFunctionWithKeywords(PyObject* self, PyObject* args, PyObject* kw);
PyObject* MyFunctionWithNoArgs(PyObject* self);
      一般我们使用的是第一种方式,函数的参数将会一个元组(tuple)的形式传进来,因此我们在c模块的函数中需要对其进行解析。Python中不能象c语言一样声明一个void类型的函数,如果你不想函数返回一个值的话,那就返回一个NONE,在这里我们可以通过Python头文件中的一个宏Py_RETURN_NONE来实现。

C模块中的函数名称其实对外部来说是不可见的,因此可以随便你命名,一般我们可以使用static函数(这在C语言里表示在当前文件以外是不可见的)。本文函数命名方式采用模块名加上函数名,例如foo_bar,这表示在模块foo中会有一个bar函数。然后就是函数映射表了,它是一个PyMethodDef结构体数组,

struct PyMethodDef {
    char* ml_name;
    PyCFunction ml_meth;
    int ml_flags;
    char* ml_doc;
};
      第一个成员ml_name是函数名,当我们在外部的Python代码中使用此模块时利用这个名称进行函数调用。ml_meth是函数地址。ml_flags告诉解释器ml_meth将会使用上述三种方法签名的哪一种,一般设置为METH_VARARGS,如果你想允许关键字参数,则可以将其与METH_KEYWORDS进行或运算。若不想接受任何参数,则可以将其设置为METH_NOARGS.最后,ml_doc字段是函数的注释文档信息,最好还是写几句吧,不然会被鄙视的。。。另外,这个表必须以{NULL,NULL,0,NULL}这样一条空记录结尾。

    模块的初始化函数是在模块被加载时被Python解释器所调用的,如果你的模块名为foo,则要求命名为initfoo.Py_InitModule3函数一般用来定义一个模块。

3,现在我们来将foo.c文件编译为一个扩展模块,使用下述命令进行编译: 

gcc -shared -I /usr/include/python2.6 foo.c -o foo.so
注意shared object的名称必须和传给Py_InitModule3函数的字符串一致,另一种可选的方式是加上module后缀,因此上述foo模块可以命名为foo.so或foomodule.so。

4,上面的编译方式可以完成任务,但更好的生成扩展模块的方法是使用distutils。首先写一个setup.py脚本:

from distutils.core import setup, Extension
setup(name = 'foo', version = '1.0', ext_modules = [Extension('foo', ['foo.c'])])
然后执行下述命令进行build: 

python ./setup.py build
这会在当前目录下生成一个build子目录,其中包含了中间生成的foo.o以及最后生成出来的foo.so。当然,最简单的方法是使用下述命令进行模块的生成和安装:

python ./setup.py install
注:由于需要获得dist-packages的写权限,最好先切换到root用户,如果直接使用su切换出现下面的错误:

su: Authentication failure
则为root用户设置一个新密码:

sudo passwd root
再用新密码切换到root用户。查看build时的详细情况,我们可以发现这么一句:

copying build/lib.linux-i686-2.6/foo.so -> /usr/local/lib/python2.6/dist-packages
 这是将生成的模块拷贝到/usr/local/lib/python2.6/dist-packages下了,这样就将我们的foo模块安装到系统中了,我们可以验证如下,在python命令行中,

import foo
dir(foo)
 结果如下: 

['__doc__','__file__','__name__','__package__','bar']
呵呵,不错吧,这个foo模块现在已经和其他系统模块一样了,原因就在于dist-packages是在sys.path这个路径中的,
5,现在我们手上已经有一个生成并安装好的C扩展模块了,剩下的就是在python代码中引入这个新模块,并调用它的方法

import foo
foo.bar()
当然,由于在c模块中的bar函数里,我们目前什么都还没做,所以现在啥都没有,在下一篇中我们实现:1)从python脚本里向C模块中传递参数。2)从C模块中返回值给外部的Python脚本


夜已经深了,这个python和c/c++,java相结合系列的第一篇就暂时写到这里。。。




本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2010/05/17/1737033.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【最全】阶乘算法!(python和C语言)
【最全】阶乘算法!(python和C语言)
54 0
c语言和python区别
c语言和python区别
57 0
Python----Python调用C语言方法
Python----Python调用C语言方法
141 0
LeCun自曝使用C语言23年之久,2年前才上手Python,还曾短暂尝试Lua
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 程序员圈子的流行风潮,过几年就怀旧风走一波。 这不,最近Twitter上刮起了一阵编程语言使用历史的风潮。
5212 0
Python: C语言
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。
665 0
Python的C/C++扩展——Python的C语言接口
Python语言最初是用C语言实现的一种脚本语言,后来被称为CPython,是因为后来又有其它语言实现的Python,比如Python实现的Python——PyPy,Java语言实现的Python——Jython,.Net实现的Python——IronPython。
1576 0
python与c语言的区别以及python的小小基础
python与c语言的区别示例展示: python交互模式: python与python3的小区别: ipython与ipython3的小区别:  我的GitHub地址:https://github.
866 0
+关注
嗯哼9925
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
双剑合璧-Python和大数据计算平台的结合
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多