您好,欢迎访问三七文档
用C++扩展Python分类:C/C++Python2010-03-1419:001183人阅读评论(0)收藏举报用C++扩展Python点击下载源码寒假学了下Python,原是想用来做游戏脚本开发的。自然而然就接触到了Python与C++的扩展与嵌入的问题。网上搜了好久,搜到的资料都是3.x之前的。由于我用的PythonInterpreter的版本是3.1,而3.1在语法、结构等等上都做了不同程度的修改——比如去掉了print语句,用print函数替代等等,以致于那些例子在3.1的PythonAPI/C下不能编译所以自己摸索了一下,总结一些跟大家分享。究其根源,是一些API/C函数发生了变化而引起的。这两天翻了下Python文档,也有了一些想法,所以写出来,与大家共享一下。今天谈谈如何用C++扩展Python——我用的是PythonAPI/C,而不是Boost.Python!对Python进行扩展——Extension,就是让Python能调用用C写的函数等等,这样便可以很轻松的对Python库进行扩展。如果你熟悉C++/C编程,并且熟悉Python操作的话,看个例子先:1我们熟练的打开VC6.0或VS2008,然后File--New--Project--Win32DLLProject。比如我们输一个AddTwoValue吧,建立一个EmptyProject,一路确定。当然,你的Python是安装在电脑里的,并且你的VC的目录中分别添加了../Include和../libs的。如果没有的话,请添加。2添加一个C++或C源文件。我添加的是C++文件:AddTwoValue.cpp。打开。3输入如下代码:[cpp:showcolumns]viewplaincopyprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······1501.#includepython.h2.#includeiostream3.usingnamespacestd;4.5.staticPyObject*AddTwoInteger(PyObject*Self,PyObject*Argvs)6.{7.intArgv1(0),Argv2(0);8.if(!PyArg_ParseTuple(Argvs,ii,&Argv1,&Argv2))9.{10.coutParseargumentsFAILED!endl;11.returnNULL;12.}13.coutArgv1+Argv2=Argv1+Argv2endl;14.Py_INCREF(Py_None);15.returnPy_None;16.}①这段程序应该不难。我们知道,在Python中,“万物皆对象”,PyObject就是Python中对象在C++中的表现形式——无论是List,还是Tuple,抑或是Dictionary、String,在用C++扩展时,都用PyObject表示。②再看其“参数”,第一个参数Self和在Python中定义类成员函数时用的Self相似——只要写上就行了。第二个就是其真正的参数了。③呃,这个PyArg_ParseTuple有点难看,先按字面意思理解:Arg—Argument,参数,Parse—解析,Tuple—就是Python中的Tuple了,也有人叫做“元组”。总的来说,这个函数就是将PyObject*的参数对象解析。如果你还知道Py_BuildValue的话,PyArg_ParseTuple就是Py_BuildValue的反向操作。将Argvs按字符串(“ii”)的格式分别解析存放到两个int型变量中。如果解析失败,则返回0。④cout这句不解释!!我们的函数只是要输出两个数的和,并不会返回什么东东,所以返回Py_None。None——呃,与Python中的None值一样——只不过Py_None是None在C++中的表现方式。⑤等等!Py_INCREF是搞么子的?看一下,INC—Increase,增加,REF—Reference,引用。也就是增加PyObject对象的引用计数。Py_DECREF—与Py_INCREF相反,只是减小PyObject对象的引用计数。⑥我们已经知道:在Python中,Python是自动分配、回收内存的,但是C++中不是这样——也许你在这儿分配了一段内存,却要一直担心没有释放它——反正我是这样的。所以,为了让Python回收废弃的内存、或者防止Python过早地自动回收内存,我们必须用Py_EDCREF和Py_INCREF来控制PyObject的引用计数。4好了,上面是我们的主要的导出函数。下面就是对这个函数的说明了——总得让Python知道我们的模块中有什么吧!接下来看:[cpp:showcolumns]viewplaincopyprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······1501.staticPyMethodDefModulesMethods[]=2.{3.{Add,AddTwoInteger,METH_VARARGS,AddTwoIntegers!},4.{NULL,NULL,0,NULL}5.};这个结构就是对模块中的所有方法、属性的说明列表。因为我们的这个模块中只有一个AddTwoInteger函数,所以只有一项。下面仔细看看各个参数:①Add—这个字符串是我们最终导出的函数名,可以在Python中调用。正如你所见,这个字符串不一定非要和我们C++中定义的函数名AddTwoInteger相同。②AddTwoInteger—这便是我们的C++中定义的导出函数的函数名了。③METH_VARARGS—这规定了Python向这个C++函数传递参数的方式。如果是METH_VARARGS,则用Tuple来传递;如果是METH_KEYWORDS,则用Dictionary的Key(键值)来传递参数。④AddTwoIntegers!—这句仍然简单。也就是AddTwoInteger函数的说明字符串。在Python中就是函数的DocString__doc__。5好!对模块中所有函数、属性的说明完了。下面对模块进行说明——总得让Python知道你的模块的组织形式等等吧。ForExample:仍然是static:[cpp:showcolumns]viewplaincopyprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······1501.staticstructPyModuleDefModuleDesc=2.{3.PyModuleDef_HEAD_INIT,4.AddTwoValue_Module,5.ThismoduleiscreatedbyC++.AnditAddtwoIntegers!,6.-1,7.ModulesMethods8.};①第一项,在Python的文档中是这样说的:“AlwaysinitializethismembertoPyModuleDef_HEAD_INIT.”也就是说,第一项总是赋为PyModlueDef_HEAD_INIT。②”AddTwoValue_Module”—这就是内置的模块名了,在Python中导入后,可以用模块名.__name__来获取这个字符串。注意:这个字符串和importModule这儿的Module没有关系!!也就是说,这儿的这个字符串并不一定是你的模块名!!③”This…..twoIntegers!”—这句字符串和Function的__doc__一样,是模块的DocString,也可以用模块名.__doc__获得。④-1——Python的文档中是这样说的:“sizeofper-interpreterstateofthemodule,or-1ifthemodulekeepsstateinglobalvariables.”意思是:置为-1的话,你的模块在全局范围。⑤ModulesMethods—很眼熟,是不?仔细一想,呃,是先前对模块中所有函数方法、属性进行描述的那个列表!注:这一步在2.x中是不必定义的。6终于到最后一项了!如果你仔细的话,你注意到前面所定义的都有一个static修饰符。接下来的这个是唯一一个没有static修饰符的函数:[c-sharp:showcolumns]viewplaincopyprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······1501.PyMODINIT_FUNCPyInit_AddTwoIntegers(void)//初始化模块2.{3.returnPyModule_Create(&ModuleDesc);4.}①好吧,PyMODINIT_FUNC:[c-sharp:showcolumns]viewplaincopyprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······1501.#ifdefined(__cplusplus)2.#definePyMODINIT_FUNCexternC__declspec(dllexport)PyObject*3.#else/*__cplusplus*/4.#definePyMODINIT_FUNC__declspec(dllexport)PyObject*可以看出,它定义了一个返回值为PyObject*的DLL导出函数。②注意这个函数名:PyInit_xxx。在3.1中这个函数名必须为PyInit_ModuleName。而ModuleName必须和你最后生成的.pyd文件的名字一样!这是为什么呢?因为在你importModuleName时,Python会自动根据这个ModuleName推导出:PyInit_ModuleName这个初始化模块函数并执行之!如果你更改了.pyd文件名的话,就会导入模块失败!切记切记!!!!注:在Python2.x版本中,这个初始化函数为InitModuleName。但是Python3.1中不是这样的。③然后是一个函数调用:PyModule_Create。其参数依然很熟悉——是描述模块信息的那个列表。这便初始化了模块。注:在Python2.x中,是用Py_InitModule来初始化的。我就着了这个道!!!找了半天Py_InitModule,楞是没找到。7上面的代码看的差不多了吧?VC目录设置好了吧?Python环境变量也合适吧?下面我们来生成。默认生成的是.dll文件,但如上文所述,我们要的是.pyd文件。VC6.0中依然很熟练的Project--Setting--Link--Out
本文标题:c介绍
链接地址:https://www.777doc.com/doc-4986794 .html