C++调用Python函数

From: http://www.flatws.cn/article/program/c/2010-08-24/9677.html

     Python代码在实现某些功能的时候非常方便,如果能够将Python代码与C++程序结合起来,那么一定会使Problem Solving方便许多(比如,游戏脚本系统)~

    从学完Python开始就一直想研究一下C++内嵌Python是怎么回事,可是每次都坚持不下来。。。今天上校内,偶然间看到同学求助,怎么实现输入表达式输出结果~我想到了Python的builtin函数eval,正好借这个机会研究一下怎么实现C++调用Python函数!

    假定您的系统中已经安装了Python,我使用的版本是2.6~

    1.配置IDE。

    我用的是VS2008,只需要将Python安装路径下的include文件夹和libs文件夹添加到C++目录中即可。步骤是:Tools -> Options -> Project & Solution -> VC++ Dir选择右上的Dropdown List,分别将include文件夹和libs文件夹添加到include和lib项中。

    2.编写Python脚本。

    为了完成自动计算值的功能,我写了如下的脚本(文件名是python_code.py):

def calculate(expression):try:        result = eval(expression)      except:print 'Eval error!'return Nonereturn result

    将这个文件与C++程序文件放到同一目录下,这样保证编译器可以根据相对路径找到。

    3.Python嵌入的方式 - 高级vs低级

    接下来进入C++内嵌Python函数的关键部分了。根据官方的帮助文档,有两个类型的Python调用,High Level与Low Level。High Level就是调用者不需要管理与Python相关的内存,只有3行代码即可,分别是Py_Initialize()来初始化解释器(注意,此时程序仍然是由C++的编译器进行编译),调用PyRun_SimpleString()其中参数是要执行的Python代码,如果是一个确定的Python文件,那么我们可以调用PyRun_SimpleFile()直接执行Python文件。最后调用Py_Finalize()方法结束解释器工作。

    使用High Level对程序员的要求非常少,基本就是会写Python代码就会在C++中调用Python的方法,但是弊端就是当前程序不能与Python的方法进行数据的交互,所以局限性非常大。

    所以,如果我们需要与Python程序进行交互,比如计算表达式的值,我们只能使用低级的方法了。

    4.Low Level程序编写步骤。

    说实话,以前几次当我想学习Python内嵌的时候都是因为看到为了进行Low Level调用而编写的冗长的C++代码,实在是太恐怖了。。可是今天静下来看一看其实只有4步:

    (1)导入要用到的模块:

     要导入模块其实很简单,首先我们需要提供模块的文件名,注意,跟Python中导入模块一样,这里的文件名不能包含".py"后缀,比如我的文件名是python_code.py,我在程序中只需要提供"python_code"这个字符串就可以了。这一部分代码如下(注意使用到的两个函数:PyString_FromString和PyImport_Import):

PyObject *pyFileName = PyString_FromString(filename.c_str());   
PyObject *pyMod = PyImport_Import(pyFileName);		// load the module

    注意,在C++中一切Python的object都是用PyObject*来代替。第一行语句将C++中的char数组转化为Python中的字符串,然后利用这个文件名导入模块!请注意函数是PyImport_Import,而不是别的。

    好了,模块导入之后我们需要验证模块导入是否成功,如果成功我们就可以进行第二步了,找到我们要调用的方法。

    (2)找到要调用的方法。

    基本原理是这样的,在C++中,如果我们有了模块,就可以获得模块对应的attr列表(dir(模块名)),然后我们就可以利用我们所需要的方法名找到我们所需要的那个attr。找到之后我们要判断时候找到成功,而且是否是可以调用的(callable)。这部分代码如下:

// load the function      
PyObject *pyFunc = PyObject_GetAttrString(pyMod, methodname.c_str());
if(pyFunc && PyCallable_Check(pyFunc))
{// talk later!!!
}  

    第一句话首先利用PyObject_GetAttrString找到我们所需的“方法”对象,然后检测对象时候有效,是否是Callable的,如果这两者检测都成功了,那么ok,进入下一步。

    (3)构造参数。

   方法有了,接下来就缺参数了。参数是以tuple的形式传递给方法的,所以我们需要一个PyObject*对象来充当一个Tuple,利用PyTuple_New方法即可。这个方法的参数是tuple内元素的个数,我认为可以理解为参数的个数。由于我的Python代码只有一个参数,所以这里我直接给1,其他情况可以根据参数的数量赋值。

    然后解释构建参数了,根据参数的不用类型,可以调用不同的方法。这里由于我在C++程序中的参数是字符串,在Python中的参数也是一个字符串,所以我使用PyString_FromString方法,其中Py是前缀,第一个String指的是在Python代码中我们需要一个String,也就是目的参数类型,而FromString顾名思义,就是C++中参数的类型。这个方法接受一个参数,也就是一个string,注意,这个string其实是char型数组。返回的结果是一个PyObject*。

    最后一步是要把构造的参数赋值给我们的Tuple,用PyTuple_SetItem方法就可以了。第一个参数是指向Tuple的PyObject指针,第二个参数是value在Tuple中的位置参数,从0开始,最后一个就是咱们的value了,这部分代码如下:

PyObject *pyParams = PyTuple_New(1);
PyObject *pyValue = PyString_FromString(expression.c_str());
PyTuple_SetItem(pyParams, 0, pyValue);

    (4)调用方法,取返回值。

    好了,大功即将告成~最后一步当然是调用方法了!利用PyObject_CallObject方法,第一个参数是指向函数的那个PyObject指针,第二个参数则是指向我们Tuple的那个PyObject指针。返回值仍然是PyObject指针对象。我们需要对它进行解析,将它转换成C++的类型。这部分代码如下:

// ok, call the function
pyValue = PyObject_CallObject(pyFunc, pyParams);
if(pyValue)
{*result = PyFloat_AsDouble(pyValue); // result is a double varreturn true;            
}    

     好了,到这里调用的全部过程就完成了,其实还不赖。最后,为了方便大家理解,我把整个代码贴了上来。

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    特别说明,如果您是用Python安装包的形式安装的Python,那么这个程序只能以Release方式运行!原因是安装包版Python在libs文件夹下只有Release版的lib文件,而debug模式需要Python26_d.lib,也就是debug模式的。如果您在运行时提示无法打开python26_d.lib文件,那么请换成Release模式,或者下载Python源码自己编译,这样就会生成_d的lib文件了!

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    由于我的水平实在有限,文中难免有错误,希望各位看到之后留言指正!谢谢各位!

#include <Python.h> // this is in <python-install-path>
#include <conio.h>
#include <iostream>
#include <string>using namespace std;bool calc(string filename, string methodname, string expression, double *result)
{PyObject *pyFileName = PyString_FromString(filename.c_str());PyObject *pyMod = PyImport_Import(pyFileName);	// load the moduleif (pyMod)										// if ok{PyObject *pyFunc = PyObject_GetAttrString(pyMod, methodname.c_str());	// load the functionif (pyFunc && PyCallable_Check(pyFunc)){PyObject *pyParams = PyTuple_New(1);PyObject *pyValue = PyString_FromString(expression.c_str());PyTuple_SetItem(pyParams, 0, pyValue);pyValue = PyObject_CallObject(pyFunc, pyParams);	// ok, call the functionif (pyValue){*result = PyFloat_AsDouble(pyValue);return true;}else{return false;}}else{return false;}}else{return false;}return false;
}int main(void)
{string filename = "python_code";	// filename is settled!string methodname = "calculate";	// method name is also settled!string expression = "";				// get user input!double result = 0.0;printf("\nPlease input the expression: ");getline(cin, expression);// first initPy_Initialize();if (calc(filename, methodname, expression, &result)){printf("\nResult is : %lf\n", result);}else{printf("\nError occurred...\n");}// last fini!Py_Finalize();getch();return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/406042.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

配置ubuntu使用console登录登录欢迎提示

使用ssh或console登陆成功后&#xff0c;ubuntu会顺序执行/etc/update-motd.d中的脚本 有些linux的登陆提示信息放在了/etc/ssh/sshd_config中的Banner配置项中 转载于:https://www.cnblogs.com/chen310/p/4431474.html

网络命令大全(9)--runas

Runas 允许用户用其他权限运行指定的工具和程序&#xff0c;而不是用户当前登录提供的权限。语法runas [{/profile/noprofile}] [/env] [/netonly] [/smartcard] [/showtrustlevels] [/trustlevel] /user:UserAccountName program 参数/profile 加载用户的配置文件。/profile 是…

java canvas 缩放图片_详解如何用HTML5 Canvas API控制图片的缩放变换

摘要&#xff1a;这篇HTML5栏目下的“详解如何用HTML5 Canvas API控制图片的缩放变换”&#xff0c;介绍的技术点是“html5_canvas、canvas、Html5、控制图片、api、图片”&#xff0c;希望对大家开发技术学习和问题解决有帮助。缩放变换scale(sx,sy)传入两个参数&#xff0c;分…

C语言中执行python代码或源程序文件(高级嵌入方式)

环境&#xff1a;Fedora12 Python2.6 C 1. 建立python源代码文件(del.py)&#xff1a; #!/usr/bin/env pythondef calculate(expression):try:result eval(expression)except:print("Eval Error!")return Nonereturn resultif __name__ "__main__":f …

向周鸿祎的360安全浏览器学互联网产品运营和推广

做互联网产品运营就要像周鸿祎一样&#xff0c;老周一直是运营流的大力倡导者&#xff0c;而360安全浏览器则是老周给我们上的产品运营又一课&#xff0c;醍醐灌顶&#xff0c;如梦初醒。 下图是截止到今年6月中国网民的浏览器使用情况图&#xff1a; 根据CNZZ的数据&#xff0…

java中的locksupport_java中线程的停止以及LockSupport工具类

看jstack输出的时候&#xff0c;可以发现很多状态都是TIMED_WAITING(parking)&#xff0c;如下所示&#xff1a;"http-bio-8080-exec-16" #70 daemon prio5 os_prio0 tid0x00007f6088027800 nid0x3a1f waiting on condition [0x00007f60fcd03000]java.lang.Thread.St…

React小结

1. setState setState更新状态的2种写法 (1). setState(stateChange, [callback])------对象式的setState 1.stateChange为状态改变对象(该对象可以体现出状态的更改) 2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用 (2). setState(updat…

4-17学习

//设置自动行数与字符换行 [label setNumberOfLines:0]; label.lineBreakMode UILineBreakModeWordWrap; /** 去除多余分割线 */ self.tableView.tableFooterView [[UIView alloc]init];转载于:https://www.cnblogs.com/pocket-mood/p/4435711.html

PyRun_SimpleFile()崩溃问题

From: http://blog.csdn.net/jq0123/article/details/1504406 PyRun_SimpleFile()造成程序崩溃&#xff0e;例程如下&#xff1a;#include "python.h"int main(){ Py_Initialize(); FILE * fp fopen("test.py", "r"); if …

翻译:Asp.net中多彩下拉框的实现

开发背景&#xff1a; 有人曾经要我开发一个根据不同选择而显示不同颜色的管理工具。我开始考虑利用下拉框来实现条目背景及显示颜色根据条目名称不同而进行变化&#xff0c;根据这个思路我在网上搜了半天也没有找到任何相关的解决方案&#xff0c;最后我想到了一个比当初需…

深入react技术栈(8):事件系统

我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号搜索前端小歌谣获取前端知识 1合成事件的绑定方式 2合成事件的实现机制 3在React中使用原生事件 4合成事件和原生事件混用 5对比react与原生事件 文章参考深入React技术栈

java mac jconsole_解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题

今天遇到了这样一种情况&#xff0c;自己的maven项目中并没有引用的jar包出现在了Maven Dependencies的依赖包中。而我在pom.xml自己没有没有引入啊.图示怀疑是自己的alibaba 的druid所依赖的包&#xff1a;com.alibabadruid1.0.14然后查看了它的相关依赖&#xff0c;果然找到了…

PyRun_SimpleString的无穷怨念

From: http://blog.csdn.net/ccat/article/details/544491 好吧&#xff0c;我承认我是个菜鸟&#xff0c;所以今天我勇敢的站出来接受大家的鄙视…… 话说早上同事喊我帮他改段程序&#xff0c;很简单&#xff0c;就是用PyRun_SimpleString函数执行一段Python脚本。错误也很直…

劳心者、劳力者或CEO、CTO各得其所,足矣

昨天在手机上看到了“清华学生借鉴百度技术自主研发手机框计算”的新闻&#xff0c;又是“计算”&#xff0c;很容易就与“云计算”联系起来了&#xff0c;挺有兴趣了解一下中国百度的“框计算”。毕竟我之前只是知道这么一个名词&#xff0c;没想到这么快就有了研发、应用&…

hdu 1754 I Hate It(线段树)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 45334 Accepted Submission(s): 17789 Problem Description很多学校流行一种比…

java numa_Java只使用2个CPU中的1个和NUMA(Neo4J)

我正在研究一个java程序来创建一个非常大的Neo4J数据库.我使用batchinserter和Executors.newFixedThreadPool来加快速度.我的Win2012R2服务器有2个cpu(26核心26超线程)和256GB NUMA架构.我的问题是,我的导入器只使用1个CPU(节点).是否有可能只使用一个javaprocess的NUMA节点&am…