使用C++扩展Python的功能详解


Posted in Python onJanuary 12, 2018

本文主要研究的是使用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,所以函数名是initPyExt。Python在导入
// 我们的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的工程,放在工程的相对路径下面就可以了。

使用

使用C++扩展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)。

总结

以上就是本文关于使用C++扩展Python的功能详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
Windows和Linux下使用Python访问SqlServer的方法介绍
Mar 10 Python
python操作redis的方法
Jul 07 Python
Python2.x利用commands模块执行Linux shell命令
Mar 11 Python
python+selenium+autoit实现文件上传功能
Aug 23 Python
python读取csv文件并把文件放入一个list中的实例讲解
Apr 27 Python
在Python中给Nan值更改为0的方法
Oct 30 Python
简单了解python PEP的一些知识
Jul 13 Python
QML用PathView实现轮播图
Jun 03 Python
python 贪心算法的实现
Sep 18 Python
OpenCV-Python模板匹配人眼的实例
Jun 08 Python
使用qt quick-ListView仿微信好友列表和聊天列表的示例代码
Jun 13 Python
Python数组变形的几种实现方法
May 30 Python
聊聊Python中的pypy
Jan 12 #Python
Python中实现switch功能实例解析
Jan 11 #Python
Python中getpass模块无回显输入源码解析
Jan 11 #Python
python版微信跳一跳游戏辅助
Jan 11 #Python
微信跳一跳python辅助脚本(总结)
Jan 11 #Python
Python用sndhdr模块识别音频格式详解
Jan 11 #Python
Python用imghdr模块识别图片格式实例解析
Jan 11 #Python
You might like
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
PHP简单获取及判断提交来源的方法
2016/04/22 PHP
laravel框架模型中非静态方法也能静态调用的原理分析
2019/11/23 PHP
用tip解决Ext列宽度不够的问题
2008/12/13 Javascript
使用Mootools动态添加Css样式表代码,兼容各浏览器
2011/12/12 Javascript
JavaScript学习小结之使用canvas画“哆啦A梦”时钟
2016/07/24 Javascript
微信小程序 require机制详解及实例代码
2016/12/14 Javascript
jQuery的ajax中使用FormData实现页面无刷新上传功能
2017/01/16 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
微信小程序实现图片预览功能
2018/01/31 Javascript
jQuery实现的点击按钮改变样式功能示例
2018/07/21 jQuery
详解Vue组件之间通信的七种方式
2019/04/14 Javascript
js实现页面图片消除效果
2020/03/24 Javascript
《javascript设计模式》学习笔记一:Javascript面向对象程序设计对象成员的定义分析
2020/04/07 Javascript
jQuery实现飞机大战小游戏
2020/07/05 jQuery
在Vue中使用Viser说明(基于AntV-G2可视化引擎)
2020/10/28 Javascript
一篇文章看懂JavaScript中的回调
2021/01/05 Javascript
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
Python Matplotlib库入门指南
2015/05/18 Python
Python数据分析之双色球中蓝红球分析统计示例
2018/02/03 Python
python OpenCV学习笔记之绘制直方图的方法
2018/02/08 Python
使用Python的Dataframe取两列时间值相差一年的所有行方法
2018/07/10 Python
Django中modelform组件实例用法总结
2020/02/10 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
2020/07/03 Python
Django中Aggregation聚合的基本使用方法
2020/07/09 Python
解决python中0x80072ee2错误的方法
2020/07/19 Python
基于python实现监听Rabbitmq系统日志代码示例
2020/11/28 Python
pycharm配置python 设置pip安装源为豆瓣源
2021/02/05 Python
凯特方迪化妆品官网:Kat Von D Beauty
2016/11/15 全球购物
捷克厨房用品购物网站:Tescoma
2018/07/13 全球购物
教育学专业实习生的自我鉴定
2013/11/26 职场文书
入党申请人的自我鉴定
2013/12/01 职场文书
宇宙与人观后感
2015/06/05 职场文书
婚庆答谢词大全
2015/09/29 职场文书
优秀创业计划书分享
2019/07/19 职场文书
javascript拖曳互换div的位置实现示例
2021/06/28 Javascript