- 浏览: 667705 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
sztime:
可以在文本框上绑定事件来禁用回车键, 我就是这样做的.在IE中 ...
form 回车自动提交问题 -
damoqiongqiu:
非常好的文章,很透彻不过有一句话小僧腆着脸补充一下:“1111 ...
为什么要用补码来做存储 -
wuyizhong:
原来如此啊。
form 回车自动提交问题 -
luliangy:
谢楼主~!
用C语言扩展Python的功能 -
kwong:
很有用,谢谢
火狐和IE 对css 样式解释的差异
Pyton和C分别有着各自的优缺点,用Python开发程序速度快,可靠性高,并且有许多现成模块可供使用,但执行速度相对较 慢;C语言则正好相反,其执行速度快,但开发效率低。为了充分利用两种语言各自的优点,比较好的做法是用Python开发整个软件框架,而用C语言实现其 关键模块。本文介绍如何利用C语言来扩展Python的功能,并辅以具体的实例讲述如何编写Python的扩展模块。
一、简介
Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型软件系统的开发过程中。
与其它普通脚本语言有所不同,Python程序员可以借助Python语言提供的API,使用C或者C++来对Python进行功能性扩展,从而即 可以利用Python方便灵活的语法和功能,又可以获得与C或者C++几乎相同的执行性能。执行速度慢是几乎所有脚本语言都具有的共性,也是倍受人们指责 的一个重要因素,Python则通过与C语言的有机结合巧妙地解决了这一问题,从而使脚本语言的应用范围得到了很大扩展。
在用Python开发实际软件系统时,很多时候都需要使用C/C++来对Python进行扩展。最常见的情况是目前已经存在一个用C编写的库,需要 在Python语言中使用该库的某些功能,此时就可以借助Python提供的扩展功能来实现。此外,由于Python从本质上讲还是一种脚本语言,某些功 能用Python实现可能很难满足实际软件系统对执行效率的要求,此时也可以借助Python提供的扩展功能,将这些关键代码段用C或者C++实现,从而 提供程序的执行性能。
本文主要介绍Python提供的C语言扩展接口,以及如何使用这些接口和C/C++语言来对Python进行功能性扩展,并辅以具体的实例讲述如何实现Python的功能扩展。
二、Python的C语言接口
Python是用C语言实现的一种脚本语言,本身具有优良的开放性和可扩展性,并提供了方便灵活的应用程序接口(API),从而使得C/C++程序 员能够在各个级别上对Python解释器的功能进行扩展。在使用C/C++对Python进行功能扩展之前,必须首先掌握Python解释所提供的C语言 接口。
2.1 Python对象(PyObject)
Python是一门面向对象的脚本语言,所有的对象在Python解释器中都被表示成PyObject,PyObject结构包含Python对象 的所有成员指针,并且对Python对象的类型信息和引用计数进行维护。在进行Python的扩展编程时,一旦要在C或者C++中对Python对象进行 处理,就意味着要维护一个PyObject结构。
在Python的C语言扩展接口中,大部分函数都有一个或者多个参数为PyObject指针类型,并且返回值也大都为PyObject指针。
2.2 引用计数
为了简化内存管理,Python通过引用计数机制实现了自动的垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所 分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时, 才真正从内存中删除Python对象。
下面的例子说明了Python解释器如何利用引用计数来对Pyhon对象进行管理:
例1:refcount.py class refcount: # etc. r1 = refcount() # 引用计数为1 r2 = r1 # 引用计数为2 del(r1) # 引用计数为1 del(r2) # 引用计数为0,删除对象 |
在C/C++中处理Python对象时,对引用计数进行正确的维护是一个关键问题,处理不好将很容易产生内存泄漏。Python的C语言接口提供了 一些宏来对引用计数进行维护,最常见的是用Py_INCREF()来增加使Python对象的引用计数增1,用Py_DECREF()来使Python对 象的引用计数减1。
2.3 数据类型
Python定义了六种数据类型:整型、浮点型、字符串、元组、列表和字典,在使用C语言对Python进行功能扩展时,首先要了解如何在C和Python的数据类型间进行转化。
2.3.1 整型、浮点型和字符串
在Python的C语言扩展中要用到整型、浮点型和字符串这三种数据类型时相对比较简单,只需要知道如何生成和维护它们就可以了。下面的例子给出了如何在C语言中使用Python的这三种数据类型:
例2:typeifs.c // build an integer PyObject* pInt = Py_BuildValue("i", 2003); assert(PyInt_Check(pInt)); int i = PyInt_AsLong(pInt); Py_DECREF(pInt); // build a float PyObject* pFloat = Py_BuildValue("f", 3.14f); assert(PyFloat_Check(pFloat)); float f = PyFloat_AsDouble(pFloat); Py_DECREF(pFloat); // build a string PyObject* pString = Py_BuildValue("s", "Python"); assert(PyString_Check(pString); int nLen = PyString_Size(pString); char* s = PyString_AsString(pString); Py_DECREF(pString); |
2.3.2 元组
Python语言中的元组是一个长度固定的数组,当Python解释器调用C语言扩展中的方法时,所有非关键字(non-keyword)参数都以元组方式进行传递。下面的例子示范了如何在C语言中使用Python的元组类型:
例3:typetuple.c // create the tuple PyObject* pTuple = PyTuple_New(3); assert(PyTuple_Check(pTuple)); assert(PyTuple_Size(pTuple) == 3); // set the item PyTuple_SetItem(pTuple, 0, Py_BuildValue("i", 2003)); PyTuple_SetItem(pTuple, 1, Py_BuildValue("f", 3.14f)); PyTuple_SetItem(pTuple, 2, Py_BuildValue("s", "Python")); // parse tuple items int i; float f; char *s; if (!PyArg_ParseTuple(pTuple, "ifs", &i, &f, &s)) PyErr_SetString(PyExc_TypeError, "invalid parameter"); // cleanup Py_DECREF(pTuple); |
2.3.3 列表
Python语言中的列表是一个长度可变的数组,列表比元组更为灵活,使用列表可以对其存储的Python对象进行随机访问。下面的例子示范了如何在C语言中使用Python的列表类型:
例4:typelist.c // create the list PyObject* pList = PyList_New(3); // new reference assert(PyList_Check(pList)); // set some initial values for(int i = 0; i < 3; ++i) PyList_SetItem(pList, i, Py_BuildValue("i", i)); // insert an item PyList_Insert(pList, 2, Py_BuildValue("s", "inserted")); // append an item PyList_Append(pList, Py_BuildValue("s", "appended")); // sort the list PyList_Sort(pList); // reverse the list PyList_Reverse(pList); // fetch and manipulate a list slice PyObject* pSlice = PyList_GetSlice(pList, 2, 4); // new reference for(int j = 0; j < PyList_Size(pSlice); ++j) { PyObject *pValue = PyList_GetItem(pList, j); assert(pValue); } Py_DECREF(pSlice); // cleanup Py_DECREF(pList); |
2.3.4 字典
Python语言中的字典是一个根据关键字进行访问的数据类型。下面的例子示范了如何在C语言中使用Python的字典类型:
例5:typedic.c // create the dictionary PyObject* pDict = PyDict_New(); // new reference assert(PyDict_Check(pDict)); // add a few named values PyDict_SetItemString(pDict, "first", Py_BuildValue("i", 2003)); PyDict_SetItemString(pDict, "second", Py_BuildValue("f", 3.14f)); // enumerate all named values PyObject* pKeys = PyDict_Keys(); // new reference for(int i = 0; i < PyList_Size(pKeys); ++i) { PyObject *pKey = PyList_GetItem(pKeys, i); PyObject *pValue = PyDict_GetItem(pDict, pKey); assert(pValue); } Py_DECREF(pKeys); // remove a named value PyDict_DelItemString(pDict, "second"); // cleanup Py_DECREF(pDict); |
三、Python的C语言扩展
3.1 模块封装
在了解了Python的C语言接口后,就可以利用Python解释器提供的这些接口来编写Python的C语言扩展,假设有如下一个C语言函数:
例6:example.c int fact(int n) { if (n <= 1) return 1; else return n * fact(n - 1); } |
该函数的功能是计算某个给定自然数的阶乘,如果想在Python解释器中调用该函数,则应该首先将其实现为Python中的一个模块,这需要编写相应的封装接口,如下所示:
例7: wrap.c #include <Python.h> PyObject* wrap_fact(PyObject* self, PyObject* args) { int n, result; if (! PyArg_ParseTuple(args, "i:fact", &n)) return NULL; result = fact(n); return Py_BuildValue("i", result); } static PyMethodDef exampleMethods[] = { {"fact", wrap_fact, METH_VARARGS, "Caculate N!"}, {NULL, NULL} }; void initexample() { PyObject* m; m = Py_InitModule("example", exampleMethods); } |
一个典型的Python扩展模块至少应该包含三个部分:导出函数、方法列表和初始化函数。
3.2 导出函数
要在Python解释器中使用C语言中的某个函数,首先要为其编写相应的导出函数,上述例子中的导出函数为wrap_fact。在Python的C语言扩展中,所有的导出函数都具有相同的函数原型:
PyObject* method(PyObject* self, PyObject* args);
该函数是Python解释器和C函数进行交互的接口,带有两个参数:self和args。参数self只在C函数被实现为内联方法(built- in method)时才被用到,通常该参数的值为空(NULL)。参数args中包含了Python解释器要传递给C函数的所有参数,通常使用Python的 C语言扩展接口提供的函数PyArg_ParseTuple()来获得这些参数值。
所有的导出函数都返回一个PyObject指针,如果对应的C函数没有真正的返回值(即返回值类型为void),则应返回一个全局的None对象(Py_None),并将其引用计数增1,如下所示:
PyObject* method(PyObject *self, PyObject *args) { Py_INCREF(Py_None); return Py_None; } |
3.3 方法列表
方法列表中给出了所有可以被Python解释器使用的方法,上述例子对应的方法列表为:
static PyMethodDef exampleMethods[] = { {"fact", wrap_fact, METH_VARARGS, "Caculate N!"}, {NULL, NULL} }; |
方法列表中的每项由四个部分组成:方法名、导出函数、参数传递方式和方法描述。方法名是从Python解释器中调用该方法时所使用的名字。参数传递 方式则规定了Python向C函数传递参数的具体形式,可选的两种方式是METH_VARARGS和METH_KEYWORDS,其中 METH_VARARGS是参数传递的标准形式,它通过Python的元组在Python解释器和C函数之间传递参数,若采用METH_KEYWORD方 式,则Python解释器和C函数之间将通过Python的字典类型在两者之间进行参数传递。
3.4 初始化函数
所有的Python扩展模块都必须要有一个初始化函数,以便Python解释器能够对模块进行正确的初始化。Python解释器规定所有的初始化函数的函数名都必须以init开头,并加上模块的名字。对于模块example来说,则相应的初始化函数为:
void initexample() { PyObject* m; m = Py_InitModule("example", exampleMethods); } |
当Python解释器需要导入该模块时,将根据该模块的名称查找相应的初始化函数,一旦找到则调用该函数进行相应的初始化工作,初始化函数则通过调 用Python的C语言扩展接口所提供的函数Py_InitModule(),来向Python解释器注册该模块中所有可以用到的方法。
3.5 编译链接
要在Python解释器中使用C语言编写的扩展模块,必须将其编译成动态链接库的形式。下面以RedHat Linux 8.0为例,介绍如何将C编写的Python扩展模块编译成动态链接库:
[xiaowp@gary code]$ gcc -fpic -c -I/usr/include/python2.2 \ -I /usr/lib/python2.2/config \ example.c wrapper.c [xiaowp@gary code]$ gcc -shared -o example.so example.o wrapper.o |
3.6 引入Python解释器
当生成Python扩展模块的动态链接库后,就可以在Python解释器中使用该扩展模块了,与Python自带的模块一样,扩展模块也是通过import命令引入后再使用的,如下所示:
[xiaowp@gary code]$ python Python 2.2.1 (#1, Aug 30 2002, 12:15:30) [GCC 3.2 20020822 (Red Hat Linux Rawhide 3.2-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> example.fact(4) 24 >>> |
四、结束语
作为一门功能强大的脚本语言,Python将被更加广泛地应用于各个领域。为了克服脚本语言执行速度慢的问题,Python提供了相应的C语言扩展 接口,通过将影响执行性能的关键代码用C语言实现,可以很大程度上提高用Python编写的脚本在运行时的速度,从而满足实际需要。
参考资料
- 可以从Python( http://www.python.org )网站着手了解所有关于Python的内容。
- 可以在Python网站上找到正式的Python C/API文档( http://www.python.org/doc/current/api/api.html )。
- 可以在Python网站上找到正式的编写Python扩展模块的文档( http://www.python.org/doc/current/api/api.html )。
发表评论
-
apns批量使用失败
2012-04-17 19:22 2481突然某一天app 调用 apns 用户莫名其妙收不到, ... -
pylons 中 wsgiapp 和 wsgicontroller 的关系
2011-09-05 02:43 685pylons 看了好久了,喜欢的他精简封装,就想它自己的 ... -
[转] Python 面试题集合
2011-07-27 01:48 1521Python 面试题集合 发布时间:2011-07- ... -
nginx 下 用fastcgi 模式使用 webpy
2011-07-24 00:23 867nginx ---------------------- ... -
【外刊IT评论】Python 程序员的进化
2011-02-11 00:07 1074不久前,在互联网上出现了一篇有趣的文章,讲的是对于同一个问题, ... -
paramiko 的ssh登录
2011-01-04 17:43 1143import paramiko socks=('192. ... -
getattribute getattr
2010-09-11 21:53 798class D(object): def ... -
python 打包【转】
2010-09-02 00:33 1644python的第三方模块越来 ... -
python 3D相关
2009-02-24 23:24 1241Python是什么>? 它不是蟒蛇,而是一种早期产生于L ... -
蛋蛋的python把老子吓死了
2009-02-13 16:23 1257今天无意中敲 python的老窝, 敲到 www.python ... -
我的第一个python应用
2009-02-12 01:47 4983我的一个python应用做完了!哈哈,自己自学python时间 ... -
网上有人实现的飞信的协议
2009-02-09 14:01 813http://cocobear.info/blog/2008/ ... -
python加cookie访问
2009-02-08 23:28 2613import httplib, urllib def t ... -
Python 中的元类编程
2009-01-05 01:56 719最近看python 遇到python的元类编程。 查到这篇文 ... -
[转]常用的python模块
2009-01-02 01:51 1765adodb:我们领导推荐的数据库连接组件 bsddb3:Be ... -
[转]制作Python的安装模块
2009-01-02 01:44 2903Python模块的安装方法: 1. 单文件模块 ... -
python 中文编码的处理
2008-12-31 19:10 4397在win下写点python的代码,对utf-8 老是处理不过来 ... -
pyinstaller 来建立linux下的python独立执行文件
2008-12-09 10:21 2482以下内容假定已安装好Python 2.4/2.5 一、下载并 ... -
stackless python
2008-11-26 18:33 2309Stackless Python 并发式编程介绍 作者: Gr ... -
python 微线程
2008-11-26 18:29 21059.4 微线程—Stackless Pyt ...
相关推荐
### 使用C语言扩展Python的功能 #### 一、引言 Python因其简洁的语法、丰富的标准库及第三方库,成为了一种流行的高级编程语言。然而,Python作为一种解释型语言,在执行速度方面不如编译型语言如C或C++。因此,在...
通过学习和实践C语言扩展Python,你可以创建高效的库,处理底层操作,或者利用现有的C库来增强Python的功能。这个过程需要对Python的内部机制有深入的理解,但一旦掌握,你将能够解锁Python开发的更广阔天地。
总结来说,文档中提到的知识点不仅覆盖了使用C语言扩展Python的基础理论,也包含了实际操作的细节,如对象的引用计数、数据类型的转换以及使用Python C API进行编程实践。掌握这些知识点,可以大大提升Python程序的...
而C语言编写的计算模块则可以被Python程序调用,提供必要的运算功能。为了实现这种编程方式,需要解决C语言和Python之间的接口问题。在这个案例中,前处理器和后处理器通过接口函数与求解器进行通信,传递必要的计算...
在讨论如何使用C语言扩展Python程序和Zope服务器时,我们首先要了解Python扩展的基础知识。Python扩展本质上是用C语言编写的动态链接库,它可以被Python解释器在运行时加载。使用C语言编写扩展的好处包括提高性能,...
本主题将深入探讨如何使用C语言编写Python的扩展模块,让Python能够调用C库。首先,我们来看看标题提到的核心概念:“用C语言编写Python的扩展模块”。 **一、Python扩展模块** Python扩展模块是用C或C++编写的,...
3. CToolkit开发:这是最灵活的扩展机制,允许用户利用ERDAS IMAGINE提供的CToolkit开发包,用C/C++语言开发出IMAGINE目前尚未提供的新功能。这包括添加新的数据格式以及输出特定数据的需求。并且,新开发的功能能够...
本文将详细探讨如何使用C++扩展Python的功能,主要涉及以下几个关键知识点: 1. **Python C API**: Python提供了C API,这是一组用C语言编写的函数,允许开发者在C++代码中直接操作Python对象。通过C API,我们可以...
4. **性能优化**:如果原C程序有性能要求,Python可以通过使用如NumPy的底层C实现或通过编写扩展模块(如使用Cython或Pybind11)来提高速度。 5. **测试与调试**:确保转换后的Python代码功能正确,通过单元测试和...
在Python的`scipy.signal`库中,`filtfilt`是一个内置函数,但用C语言重写这个功能可以提高执行速度和降低内存使用。 `filtfilt`函数的主要功能是应用线性滤波器两次,一次正向,一次反向。这种方法的优点是输出...
SPI-Py:硬件 SPI 作为 Python 的 C 扩展 示例用法 下面的命令可以在test_script.py文件中找到。 安装库后,通过以下方式将 spi 模块导入 Python 代码: 更多详情、使用方法,请下载后阅读README.md文件
C语言编译器(Python版)是一个创新的项目,它使用Python编程语言来实现一个能够解析和编译C语言源代码的工具。这样的编译器通常被称为“源到源”编译器,因为它将C语言的源代码转换为另一种形式的源代码,可能是...
"Python实现C语言经典100例"这个项目,旨在通过将C语言的经典例子用Python进行重写,帮助学习者更好地理解和应用Python,同时也展示了两种语言在解决问题上的异同。 1. **基础知识** - **Python语法**:Python的...
Extend Python with C 实际上ctypes、Python C API或者基于API的Cython,逻辑都是: 接收Python对象->转换为C对象->调用C函数->返回值转换为Python对象->返回 的流程,较为值得关切的几点是: 指针传参问题 数组传递...
8. **C API更新**:对于需要使用C语言扩展Python功能的开发者,Python 2.3的C API也进行了一些改进,使其更易于编写高效的Python扩展。 下载的"Python-2.3.2-1.exe"是Windows平台上的安装程序,用户可以通过运行这...
WiringPi是为树莓派(Raspberry Pi)设计的一个开源库,它提供了C语言和Python两种接口,使得用户能够轻松地控制树莓派的GPIO(General Purpose Input/Output)引脚。GPIO引脚是树莓派硬件扩展的重要部分,通过它们,...
通过深入学习Python-2.0.1的C语言源码,开发者不仅可以更好地理解Python的内部工作原理,还能提升自己的C语言编程技能,并为优化Python应用、编写扩展模块或解决性能问题提供参考。尽管这是一个较旧的版本,但它仍然...