如何将c语言程序封装供python调用-转:用C语言扩展Python的功能_第1页
如何将c语言程序封装供python调用-转:用C语言扩展Python的功能_第2页
如何将c语言程序封装供python调用-转:用C语言扩展Python的功能_第3页
如何将c语言程序封装供python调用-转:用C语言扩展Python的功能_第4页
如何将c语言程序封装供python调用-转:用C语言扩展Python的功能_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

如何将c语⾔程序封装供python调⽤_转:⽤C语⾔扩展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.1Python对象(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.pyclassrefcount:#etc.r1=refcount()#引⽤计数为1r2=r1#引⽤计数为2del(r1)#引⽤计数为1del(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//buildanintegerPyObject*pInt=Py_BuildValue("i",2003);assert(PyInt_Check(pInt));inti=PyInt_AsLong(pInt);Py_DECREF(pInt);//buildafloatPyObject*pFloat=Py_BuildValue("f",3.14f);assert(PyFloat_Check(pFloat));floatf=PyFloat_AsDouble(pFloat);Py_DECREF(pFloat);//buildastringPyObject*pString=Py_BuildValue("s","Python");assert(PyString_Check(pString);intnLen=PyString_Size(pString);char*s=PyString_AsString(pString);Py_DECREF(pString);2.3.2元组Python语⾔中的元组是⼀个长度固定的数组,当Python解释器调⽤C语⾔扩展中的⽅法时,所有⾮关键字(non-keyword)参数都以元组⽅式进⾏传递。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的元组类型:例3:typetuple.c//createthetuplePyObject*pTuple=PyTuple_New(3);assert(PyTuple_Check(pTuple));assert(PyTuple_Size(pTuple)==3);//settheitemPyTuple_SetItem(pTuple,0,Py_BuildValue("i",2003));PyTuple_SetItem(pTuple,1,Py_BuildValue("f",3.14f));PyTuple_SetItem(pTuple,2,Py_BuildValue("s","Python"));//parsetupleitems

inti;floatf;char*s;if(!PyArg_ParseTuple(pTuple,"ifs",&i,&f,&s))PyErr_SetString(PyExc_TypeError,"invalidparameter");//cleanupPy_DECREF(pTuple);2.3.3列表Python语⾔中的列表是⼀个长度可变的数组,列表⽐元组更为灵活,使⽤列表可以对其存储的Python对象进⾏随机访问。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的列表类型:例4:typelist.c//createthelistPyObject*pList=PyList_New(3);//newreferenceassert(PyList_Check(pList));//setsomeinitialvaluesfor(inti=0;i<3;++i)PyList_SetItem(pList,i,Py_BuildValue("i",i));//insertanitemPyList_Insert(pList,2,Py_BuildValue("s","inserted"));//appendanitemPyList_Append(pList,Py_BuildValue("s","appended"));//sortthelistPyList_Sort(pList);//reversethelistPyList_Reverse(pList);//fetchandmanipulatealistslicePyObject*pSlice=PyList_GetSlice(pList,2,4);//newreferencefor(intj=0;j<PyList_Size(pSlice);++j){PyObject*pValue=PyList_GetItem(pList,j);assert(pValue);}Py_DECREF(pSlice);//cleanupPy_DECREF(pList);

2.3.4字典Python语⾔中的字典是⼀个根据关键字进⾏访问的数据类型。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的字典类型:例5:typedic.c//createthedictionaryPyObject*pDict=PyDict_New();//newreferenceassert(PyDict_Check(pDict));//addafewnamedvaluesPyDict_SetItemString(pDict,"first",Py_BuildValue("i",2003));PyDict_SetItemString(pDict,"second",Py_BuildValue("f",3.14f));//enumerateallnamedvaluesPyObject*pKeys=PyDict_Keys();//newreferencefor(inti=0;i<PyList_Size(pKeys);++i){PyObject*pKey=PyList_GetItem(pKeys,i);PyObject*pValue=PyDict_GetItem(pDict,pKey);assert(pValue);}Py_DECREF(pKeys);//removeanamedvaluePyDict_DelItemString(pDict,"second");//cleanupPy_DECREF(pDict);三、Python的C语⾔扩展3.1模块封装在了解了Python的C语⾔接⼝后,就可以利⽤Python解释器提供的这些接⼝来编写Python的C语⾔扩展,假设有如下⼀个C语⾔函数:例6:example.cintfact(intn){if(n<=1)return1;elsereturnn*fact(n-1);}

该函数的功能是计算某个给定⾃然数的阶乘,如果想在Python解释器中调⽤该函数,则应该⾸先将其实现为Python中的⼀个模块,这需要编写相应的封装接⼝,如下所⽰:例7:wrap.c#includePyObject*wrap_fact(PyObject*self,PyObject*args){intn,result;if(!PyArg_ParseTuple(args,"i:fact",&n))returnNULL;result=fact(n);returnPy_BuildValue("i",result);}staticPyMethodDefexampleMethods[]={{"fact",wrap_fact,METH_VARARGS,"CaculateN!"},{NULL,NULL}};voidinitexample(){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-inmethod)时才被⽤到,通常该参数的值为空(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);returnPy_None;

}3.3⽅法列表⽅法列表中给出了所有可以被Python解释器使⽤的⽅法,上述例⼦对应的⽅法列表为:staticPyMethodDefexampleMethods[]={{"fact",wrap_fact,METH_VARARGS,"CaculateN!"},{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来说,则相应的初始化函数为:voidinitexample(){PyObject*m;m=Py_InitModule("example",exampleMethods);}当Python解释器需要导⼊该模块时,将根据该模块的名称查找相应的初始化函数,⼀旦找到则调⽤该函数进⾏相应的初始化⼯作,初始化函数则通过调⽤Python的C语⾔扩展接⼝所提供的函数Py_InitModule(),来向Python解释器注册该模块中所有可以⽤到的⽅法。3.5编译链接要在Python解释器中使⽤C语⾔编写的扩展模块,必须将其编译成动态链接库的形式。下⾯以RedHatLinux8.0为例,介绍如何将

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论