python——C/C++&python合♂体开发

之前开发python一直都是用C++的system()调用脚本执行某些相关处理

然而需要返回值时,却感觉到了相当的蛋疼。即使我们可以强行夺取system的返回值(py代码里sys.exit(0))来实现整型的返回值

但其也不是一个长久之计。更何况如果我们需要其它类型的返回值呢?比如说最常见的字符串类型。那就只能让两者关联

下面我们就来看看 如何让python和c++完美的结♂合在一起~

①我们先建立一个python脚本,比如说实现A+B的功能

#retStr_test function 
import sys

def retStr_test(a,b): 
    print "MDZZ:"+str(a)+"+"+str(b)+"="+str(a+b)+"!"
    return "MDZZ:"+str(a)+"+"+str(b)+"="+str(a+b)+"!"

#retStr_test(int(sys.argv[1]),int(sys.argv[2]))      

最后一行为测试时的入口,关联C++程序时请注释掉~

好,确认我们python里的函数retStr_test没有问题后,进行下一步

②配置python环境

导入python相关的头文件与lib包

③如果出现【无法打开文件“python27_d.lib】报错的话

修改pyconfig.h文件

将这里的python27_d.lib修改为python27.lib,也可以复制一份python27.lib名为python27_d.lib

/* For an MSVC DLL, we can nominate the .lib files used by extensions */
#ifdef MS_COREDLL
#   ifndef Py_BUILD_CORE /* not building the core - must be an ext */
#       if defined(_MSC_VER)
            /* So MSVC users need not specify the .lib file in
            their Makefile (other compilers are generally
            taken care of by distutils.) */
#           ifdef _DEBUG
#               pragma comment(lib,"python27.lib")
#           else
#               pragma comment(lib,"python27.lib")
#           endif /* _DEBUG */
#       endif /* _MSC_VER */
#   endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */

④如果编译时出现一些外部引用报错的话,例如:

修改object.h

注释掉这个就好了

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

这些是由于debug问题,你也可以选择release神马的……

接下来C++代码开发

代码中引入python头文件#include "Python.h"

介绍一些相应函数:

PyObject python对象的结构体,我们与python交互时都要以这个为类型

Py_Initialize(); 初始

Py_Finalize(); 关闭

Py_IsInitialized()检查初始是否成功

PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')"); 添加当前路径

PyImport_Import(PyObject *pName);载入脚本

PyString_FromString(string s);为了配合上一个函数,将str转换为PyObject

PyModule_GetDict(PyObject *pName)通过引入的模块转为一个字典(其实也是PyObject)

PyDict_GetItemString(PyObject *pDict, string s);上一个转换完了字典对象,以及函数名s

PyTuple_New(int n); 参数个数

PyTuple_SetItem 参数进栈,具体格式见代码注释

PyObject_CallObject(PyObject *pFunc, PyObject *pArgs)调用脚本,返回PyObject类型

PyArg_Parse(PyObject *result, "s", &strRet);格式转换

完整代码如下:

// call_py_test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "Python.h" 
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char** argv) 
{ 
    // 初始化Python 
    //在使用Python系统前,必须使用Py_Initialize对其 
    //进行初始化。它会载入Python的内建模块并添加系统路 
    //径到模块搜索路径中。这个函数没有返回值,检查系统 
    //是否初始化成功需要使用Py_IsInitialized。 

    Py_Initialize(); 

    // 检查初始化是否成功 
    if ( !Py_IsInitialized() ) 
    { 
        return -1; 
    } 

    // 添加当前路径 
    //把输入的字符串作为Python代码直接运行,返回0 
    //表示成功,-1表示有错。大多时候错误都是因为字符串 
    //中有语法错误。 
    PyRun_SimpleString("import sys"); 
    PyRun_SimpleString("sys.path.append('./')"); 
    PyObject *pName,*pModule,*pDict,*pFunc,*pArgs; 

    // 载入名为pytest的脚本 
    pName = PyString_FromString("pytest"); //我的脚本直接放在了debug下
    pModule = PyImport_Import(pName); 
    if ( !pModule ) 
    { 
        printf("can't find pytest.py"); 
        getchar(); 
        return -1; 
    } 
    pDict = PyModule_GetDict(pModule); 
    if ( !pDict ) 
    { 
        return -1; 
    } 

    // 找出函数名为retStr_test的函数 
    pFunc = PyDict_GetItemString(pDict, "retStr_test"); 
    if ( !pFunc || !PyCallable_Check(pFunc) ) 
    { 
        printf("can't find function [retStr_test]"); 
        getchar(); 
        return -1; 
    } 

    // 参数进栈 
    *pArgs; 
    pArgs = PyTuple_New(2); 

    //  PyObject* Py_BuildValue(char *format, ...) 
    //  把C++的变量转换成一个Python对象。当需要从 
    //  C++传递变量到Python时,就会使用这个函数。此函数 
    //  有点类似C的printf,但格式不同。常用的格式有 
    //  s 表示字符串, 
    //  i 表示整型变量, 
    //  f 表示浮点数, 
    //  O 表示一个Python对象。 

    int arg1=233;       //定义第一个参数 
        int arg2=250;       //定义第二个参数 
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("i",arg1)); 
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i",arg2)); 

    // 调用Python函数 
    
    char* strRet;
    PyObject* result=PyObject_CallObject(pFunc, pArgs); 
    //返回值类型转换
    PyArg_Parse(result, "s", &strRet);

    cout<<"strRet="<<strRet<<endl;

    Py_DECREF(pName); 
    Py_DECREF(pArgs); 
    Py_DECREF(pModule); 

    // 关闭Python 
    Py_Finalize(); 
    system("pause");
    return 0; 
} 

部分内容学习与http://blog.chinaunix.net/uid-20564848-id-73553.html

VS2010完整项目工程关于python关联c++开发的demo 下载地址:http://download.csdn.net/detail/sm9sun/9696866

虽然我们实现了python与c++的交互,但是是否采用这种手段还要根据具体情况分析。

比如说其调用的性能、PyObject对象强转后的准确性等一系列问题都需要我们长期去测试。

个人认为,如果交互次数不是很多的话,也可以考虑以读写文本的形式进行参数的交互

这样做的好处:

①免去了配置环境及其相关开发的繁琐流程

②内容传递相对来说较安全准确

③其内容可以留存,相当于log

④完全没有语言、平台等限制之前开发python一直都是用C++的system()调用脚本执行某些相关处理

然而需要返回值时,却感觉到了相当的蛋疼。即使我们可以强行夺取system的返回值(

py代码里sys.exit(0)

)来实现整型的返回值

但其也不是一个长久之计。更何况如果我们需要其它类型的返回值呢?比如说最常见的字符串类型。那就只能让两者关联

下面我们就来看看 如何让python和c++完美的结♂合在一起~

①我们先建立一个python脚本,比如说实现A+B的功能

#retStr_test function 
import sys

def retStr_test(a,b): 
    print "MDZZ:"+str(a)+"+"+str(b)+"="+str(a+b)+"!"
    return "MDZZ:"+str(a)+"+"+str(b)+"="+str(a+b)+"!"

#retStr_test(int(sys.argv[1]),int(sys.argv[2]))   

最后一行为测试时的入口,关联C++程序时请注释掉~

image

好,确认我们python里的函数retStr_test没有问题后,进行下一步

②配置python环境

导入python相关的头文件与lib包

image

③如果出现【无法打开文件“python27_d.lib】报错的话

修改pyconfig.h文件

image

将这里的python27_d.lib修改为python27.lib,也可以复制一份python27.lib名为python27_d.lib

/* For an MSVC DLL, we can nominate the .lib files used by extensions */
#ifdef MS_COREDLL
#   ifndef Py_BUILD_CORE /* not building the core - must be an ext */
#       if defined(_MSC_VER)
            /* So MSVC users need not specify the .lib file in
            their Makefile (other compilers are generally
            taken care of by distutils.) */
#           ifdef _DEBUG
#               pragma comment(lib,"python27.lib")
#           else
#               pragma comment(lib,"python27.lib")
#           endif /* _DEBUG */
#       endif /* _MSC_VER */
#   endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */</pre>

④如果编译时出现一些外部引用报错的话,例如:

image

修改object.h

image

注释掉这个就好了

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

这些是由于debug问题,你也可以选择release神马的……

接下来C++代码开发

代码中引入python头文件#include "Python.h"

介绍一些相应函数:

PyObject python对象的结构体,我们与python交互时都要以这个为类型

Py_Initialize(); 初始

Py_Finalize(); 关闭

Py_IsInitialized()检查初始是否成功

PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')"); 添加当前路径

PyImport_Import(PyObject *pName);载入脚本

PyString_FromString(string s);为了配合上一个函数,将str转换为PyObject

PyModule_GetDict(PyObject *pName)通过引入的模块转为一个字典(其实也是PyObject)

PyDict_GetItemString(PyObject *pDict, string s);上一个转换完了字典对象,以及函数名s

PyTuple_New(int n); 参数个数

PyTuple_SetItem 参数进栈,具体格式见代码注释

PyObject_CallObject(PyObject *pFunc, PyObject *pArgs)调用脚本,返回PyObject类型

PyArg_Parse(PyObject *result, "s", &strRet);格式转换

完整代码如下:

// call_py_test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "Python.h" 
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char** argv) 
{ 
    // 初始化Python 
    //在使用Python系统前,必须使用Py_Initialize对其 
    //进行初始化。它会载入Python的内建模块并添加系统路 
    //径到模块搜索路径中。这个函数没有返回值,检查系统 
    //是否初始化成功需要使用Py_IsInitialized。 

    Py_Initialize(); 

    // 检查初始化是否成功 
    if ( !Py_IsInitialized() ) 
    { 
        return -1; 
    } 

    // 添加当前路径 
    //把输入的字符串作为Python代码直接运行,返回0 
    //表示成功,-1表示有错。大多时候错误都是因为字符串 
    //中有语法错误。 
    PyRun_SimpleString("import sys"); 
    PyRun_SimpleString("sys.path.append('./')"); 
    PyObject *pName,*pModule,*pDict,*pFunc,*pArgs; 

    // 载入名为pytest的脚本 
    pName = PyString_FromString("pytest"); //我的脚本直接放在了debug下
    pModule = PyImport_Import(pName); 
    if ( !pModule ) 
    { 
        printf("can't find pytest.py"); 
        getchar(); 
        return -1; 
    } 
    pDict = PyModule_GetDict(pModule); 
    if ( !pDict ) 
    { 
        return -1; 
    } 

    // 找出函数名为retStr_test的函数 
    pFunc = PyDict_GetItemString(pDict, "retStr_test"); 
    if ( !pFunc || !PyCallable_Check(pFunc) ) 
    { 
        printf("can't find function [retStr_test]"); 
        getchar(); 
        return -1; 
    } 

    // 参数进栈 
    *pArgs; 
    pArgs = PyTuple_New(2); 

    //  PyObject* Py_BuildValue(char *format, ...) 
    //  把C++的变量转换成一个Python对象。当需要从 
    //  C++传递变量到Python时,就会使用这个函数。此函数 
    //  有点类似C的printf,但格式不同。常用的格式有 
    //  s 表示字符串, 
    //  i 表示整型变量, 
    //  f 表示浮点数, 
    //  O 表示一个Python对象。 

    int arg1=233;       //定义第一个参数 
        int arg2=250;       //定义第二个参数 
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("i",arg1)); 
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i",arg2)); 

    // 调用Python函数 

    char* strRet;
    PyObject* result=PyObject_CallObject(pFunc, pArgs); 
    //返回值类型转换
    PyArg_Parse(result, "s", &strRet);

    cout<<"strRet="<<strRet<<endl;

    Py_DECREF(pName); 
    Py_DECREF(pArgs); 
    Py_DECREF(pModule); 

    // 关闭Python 
    Py_Finalize(); 
    system("pause");
    return 0; 
} 
image

部分内容学习与http://blog.chinaunix.net/uid-20564848-id-73553.html

VS2010完整项目工程关于python关联c++开发的demo 下载地址:http://download.csdn.net/detail/sm9sun/9696866

虽然我们实现了python与c++的交互,但是是否采用这种手段还要根据具体情况分析。

比如说其调用的性能、PyObject对象强转后的准确性等一系列问题都需要我们长期去测试。

个人认为,如果交互次数不是很多的话,也可以考虑以读写文本的形式进行参数的交互

这样做的好处:

①免去了配置环境及其相关开发的繁琐流程

②内容传递相对来说较安全准确

③其内容可以留存,相当于log

④完全没有语言、平台等限制

原文地址:http://m.blog.csdn.net/sm9sun/article/details/53392760

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342