侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

Python  /  管理员 发布于 7年前   180

本文主要研究的是使用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的工程,放在工程的相对路径下面就可以了。

使用

可能的问题

里面的这些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+matplotlib绘制旋转椭圆实例代码
    下一条:
    聊聊Python中的pypy
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客