之前开发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++程序时请注释掉~
好,确认我们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 */</pre>
④如果编译时出现一些外部引用报错的话,例如:
修改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
④完全没有语言、平台等限制