这篇文章主要介绍了使用 C++ 扩展 Python 的功能详解, 具有一定借鉴价值, 需要的朋友可以参考下
本文主要研究的是使用 C++ 扩展 Python 的功能的相关问题, 具体如下
环境
VS2005Python2.5.4Windows7(32 位)
简介
长话短说, 这里说的扩展 Python 功能与直接用其它语言写一个动态链接库, 然后让 Python 来调用有点不一样 (虽然本质是一样的) 而是指使用 Python 本身提供的 API, 使用 C++ 来对 Python 进行功能性扩展, 可以这样理解, 使用更高效的语言实现一些算法计算等等需要更高执行效率的核心 (或者需要与系统进行密切交互的) 模块, 然后让 Python 像调用内建标准库的方式来调用这些模块, 听起来是不是很诱人?! 在软件技术高速发展的今天, 借助几种计算机语言来实现一个系统的例子数不胜数, 目的不外乎就是性能和便利的平衡譬如本文要讨论的使用 C++ 来扩展 Python 就是 Python 和 C++ 的一种巧妙的有机结合, 好处不言而喻, 既可以获得和 C++ 相似的执行性能, 又可以利用 Python 的开发灵活性由于 Python 本身是使用 C 实现的, 二者结合起来还是比较容易的
基本流程
本文不适合这样的读者对 Python 完全不了解或者对 C\C++ 完全不了解, 道理你们懂的另外就是 Python 里面有 6 种基本数据类型你需要了解如何在 C 和 Python 之间对这些类型进行转化(这不在本文讨论范围, 可以参考[1])
言归正传, 感觉前面说得太多了, 实际上很简单, 因此我决定少说多做一个 C++ 的 Python 扩展模块至少应该有导出函数, 方法列表和初始化函数三个部分我们用 VS2005 这个强大的工具开工! 一般来说, 你应该建一个 Dll 工程 (至于使用 exe 来扩展 Python 可以不可以, 暂时还没研究过) 下面按部就班的说明(关键说明在注释部分)
一初始化函数
- //-------------------------------------------------------------------------
- // 函数 : initPyExt
- // 功能 : 初始化函数
- // 返回值 :PyMODINIT_FUNC
- // 附注 : 注意, 这个函数的名字不能改动必须是 init + 模块名字,
- // 我们的模块名字是 PyExt, 所以函数名是 initPyExtPython 在导入
- // 我们的 PyExt 模块时, 会找到这个函数, 并调用这个函数实现的
- // 功能很简单, 通过调用 Py_InitModule 将模块名字和映射表结合起
- // 来, 它的意思是说 PyExt 这个模块使用 PyExtMethods 这个映射表
- //-------------------------------------------------------------------------
- PyMODINIT_FUNCinitPyExt()
- {
- Py_InitModule("PyExt",PyExtMethods);
- }
二方法列表
- /*
- 方法列表, 这个是一个 C 结构数组把需要扩展的函数都映射到这个表里
- 那么 Python 就知道你的这个扩展模块支持一些什么方法了表的第一个字
- 段是方法名字, 也是通过 Python 来调用时的名字第二个字段是导出函数,
- 是真正调用的函数, 也是 C\C++ 实现的函数第三个参数是指明 Python 向
- C\C++ 函数传递参数的形式可选的两种方式是 METH_VARARGS 和
- METH_KEYWORDS, 其中 METH_VARARGS 是参数传递的标准形式, 它通
- 过 Python 的元组在 Python 解释器和 C 函数之间传递参数, 若采用
- METH_KEYWORD 方式, 则 Python 解释器和 C 函数之间将通过 Python 的字典
- 类型在两者之间进行参数传递第四个字段是这个函数的说明如果你在
- python 里来 help 这个函数, 将显示这个说明相当于在 python 里的函数的文档说明
- */
- staticPyMethodDefPyExtMethods[]=
- {
- {"Add", Add,METH_VARARGS,"Addtwo number - edit by magictong."},
- {"ExecSystem",ExecSystem,METH_VARARGS,"Execute a shell command - edit bymagictong." },
- {NULL,NULL, 0,NULL}
- };
三导出函数
- //-------------------------------------------------------------------------
- // 函数 : Add
- // 功能 : 这是一个加法函数
- // 返回值 :PyObject*
- // 参数 : PyObject*self 这个参数我们暂时不用理会
- // 参数 : PyObject*args 是一个参数列表, 我们需要从它解析出参数
- // 附注 :
- // 所有的导出函数都具有相同的原型:
- // PyObject*method(PyObject* self, PyObject* args);
- //PyArg_ParseTuple 来完成解析参数任务它的第一个参数是 args,
- // 就是我们要转换的参数第二个是格式符号 "s" 代表是个 string
- // 从 args 里提取一个参数就写 "s", 两个的话就写 "s|s", 如果是一个
- // string, 一个 int, 就写 "s|i", 有点和 printf 类似哦第三个参数就是
- // 提取出来的参数放置的真正位置必须传递这个参数的地址
- //-------------------------------------------------------------------------
- staticPyObject*Add(PyObject*self,PyObject*args)
- {
- intx = 0 ;
- inty = 0;
- intz = 0;
- if(!PyArg_ParseTuple(args,"i|i", &x, &y))
- returnNULL;
- z=x +y;
- returnPy_BuildValue("i",z);
- /*
- 调用完之后我们需要返回结果这个结果是 c 的 type 或者是我们自己定义的类型
- 必须把他转换成 PyObject, 让 python 认识这个用 Py_BuildValue 来完成他
- 是 PyArg_ParseTuple 的逆过程他的第一个参数和 PyArg_ParseTuple 的第二个
- 参数一样, 是个格式化符号第三个参数是我们需要转换的参数 Py_BuildValue
- 会把所有的返回只组装成一个 tutple 给 python
- 如果对应的 C 函数没有返回值(即返回值类型为 void), 则应返回一个全局的 None
- 对象(Py_None), 并将其引用计数增, 如下所示:
- Py_INCREF(Py_None);
- returnPy_None;
- */
- }
四再加点功能
- intcmd(constchar* arg)
- {
- returnsystem(arg);
- }
- staticPyObject*ExecSystem(PyObject*self,PyObject*args)
- {
- constchar*command;
- if(!PyArg_ParseTuple(args,"s", &command))
- returnNULL;
- intn =cmd(command);
- returnPy_BuildValue("i",n);
- }
编译
开编, 编译出来的 PyExt.dll 文件改名为 PyExt.pyd 放入 Python 的 C:\Python25\DLLs 目录就可以全局使用了, 如果你只想某个 Python 的工程, 放在工程的相对路径下面就可以了
使用
可能的问题
里面的这些 PyMODINIT_FUNC, 与 Python 相关的宏和定义在哪里呢? 定义下 #include<Python.h > 就可以了, 但是定义了之后提示 Python.h 找不到还是编译不过怎么办? 这说明你没有安装 Python 或者安装了但是没有把头文件路径引入 Path 环境变量, 或者你把 Python 的 include 目录加入工程的附加包含目录(Additional IncludeDirectories), 一般是 C:\Python25\include 这个目录, 其中 C:\Python25 是 Python 的安装目录, 按你机器的实际情况配置)
如果提示: Error 1 fatal error LNK1104:cannot open file 'python25_d.lib' 类似这样的错误, 一般可能是没有安装 Python 的开发版本, 没关系, 你使用 Release 编译一下, 如果还不行, 就把 C:\Python25\libs 目录加入工程的附加库目录(Additional LibraryDirectories)
来源: http://www.phperz.com/article/18/0223/362735.html