C++ 调用Python

由于mitk.net被人恶意抢注, 中科院分子影像重点实验室的www.mitk.net 改到 www.mitk.net.cn

 

一、环境配置

            开发工具: VS2015、python 3.7 64位

            系统:windows 64位

下载和安装64位  python3.7 https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe

我的是安装到了“E:\workspace\pythonLibX64\ ”   如下图:

VS2015属性页配置如下,包含目录“E:\workspace\pythonLibX64\include”,库目录“E:\workspace\pythonLibX64\libs”。链接器>>输入>>附加依赖项中添加 “python37.lib”:

二、代码

 

python:文件名  hello.py


def HelloWorld():
    print("py_print>>Hello world!")
    return "return>>Hello world!"

def Add(a,b):
    print("py_print>> run {} + {}".format(a,b))
    return a+b

def TestDict(input_dict):
     print("py_print>>input: {}".format(input_dict))
     input_dict['Age']=100
     return input_dict

class Person(object):
    name="chaoen hu"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    
    def greet(self, you):
        print("py_print>> 我是 {}, 欢迎 {} 来到CASMI.".format(self.name, you))

 

C++ 文件名 main.cpp

注意

1) 使用QT时#include "python.h" 请放在其它#include "Q*.h"之前,目的是为了防止命名冲突。

2) 把Python安装目录下的python37.dll 复制到本工程生成的exe 目录下。

/*
1) 初始化Python调用环境
2) 加载对应的Python模块
3) 加载对应的Python函数
4) 将参数转化为Python元组类型
5) 调用Python函数并传入参数元组
6) 获取返回值
7) 根据Python函数的定义解析返回值
*/


#include "python.h"
#include <iostream> 
// Python安装目录
#define Py_Home L"E:/workspace/pythonLibX64"
// python 工作空间(你的Python文件所在目录)
#define Pysys_Path "sys.path.append('E:/workspace/pyDLL/')"
#define Py_ErrorAndExit(X)   printf(X);  PyErr_Print(); return -1;

int HelloWorld(PyObject *pmodule);
int Add(PyObject *pmodule, int a, int b);
int TestTransferDict(PyObject *pmodule, char *name, int age);
int TestClass(PyObject *pmodule);

int main()
{

	/*>>>>>1) 初始化Python调用环境<<<<<<<<<*/
	Py_SetPythonHome(Py_Home);
	Py_Initialize();
	if (!Py_IsInitialized()) {
		Py_ErrorAndExit("初始化失败");
	}
	// python 工作空间(你的Python文件所在目录)
	PyRun_SimpleString("import sys");
	// PyRun_SimpleString 函数执行Python命令
	PyRun_SimpleString(Pysys_Path);
	/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<*/

	/*>>>>>2) 加载对应的Python模块<<<<<<<<<*/
	// 导入hello.py模块
	PyObject *pmodule = PyImport_ImportModule("hello");
	if (!pmodule)
	{
		Py_ErrorAndExit("加载模型失败");
	}
	/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<*/

	std::cout << "/______测试调用HelloWorld______/" << std::endl;
	HelloWorld(pmodule);
	std::cout << "/____________________________/" << std::endl;
	std::cout << std::endl;

	std::cout << "/______测试调用ADD__5 + 7______/" << std::endl;
	Add(pmodule,5,7);
	std::cout << "/____________________________/" << std::endl;
	std::cout << std::endl;

	std::cout << "/______测试调用TestDict______/" << std::endl;
	TestTransferDict(pmodule, "casmi", 18);
	std::cout << "/____________________________/" << std::endl;
	std::cout << std::endl;

	std::cout << "/______测试调用TestClass______/" << std::endl;
	TestClass(pmodule);
	std::cout << "/____________________________/" << std::endl;
	std::cout << std::endl;

	/*>>>>>>>>> 结束和释放<<<<<<<<<*/
	Py_DECREF(pmodule);
	Py_Finalize();
	system("pause");
	return 0;
}

int HelloWorld(PyObject *pmodule)
{
	// 3) 加载对应的Python函数
	PyObject * pFunc_HelloWorld = NULL;
	pFunc_HelloWorld = PyObject_GetAttrString(pmodule, "HelloWorld");
	if (!pFunc_HelloWorld)
	{
		Py_ErrorAndExit("加载HelloWorld函数失败");
	}
	/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<*/

	// 5) 调用函数 6) 获取返回值
	PyObject *pReturn = NULL;
	pReturn = PyEval_CallObject(pFunc_HelloWorld, NULL);
	if (!pReturn)
	{
		Py_ErrorAndExit("获取返回值失败");
	}
	// 可以释放函数
	Py_DECREF(pFunc_HelloWorld);

	// 7) 根据Python函数的定义解析返回值
	char *result = "";
	PyArg_Parse(pReturn, "s", &result);
	Py_DECREF(pReturn); // 释放
	
	std::cout << "C 函数获取的返回值: ";
	std::cout << result << std::endl;

}

int Add(PyObject *pmodule,int a,int b)
{
	// 3) 加载对应的Python函数
	PyObject * pFunc = NULL;
	pFunc = PyObject_GetAttrString(pmodule, "Add");
	if (!pFunc)
	{
		Py_ErrorAndExit("加载Add函数失败");
	}

	//4) 创建2个参数:将参数转化为Python元组类型
	PyObject *pArgs = PyTuple_New(2);
	//0---序号  "i" 表示创建int型变量, a 参数值 
	PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", a));
	PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", b));

	// 5) 调用函数 6) 获取返回值
	PyObject *pReturn = NULL;
	pReturn = PyEval_CallObject(pFunc, pArgs);
	Py_DECREF(pFunc);// 释放
	Py_DECREF(pArgs);// 释放

	//将返回值转换为int类型 
	int result;
	PyArg_Parse(pReturn, "i", &result);    //i表示转换成int型变量
	Py_DECREF(pReturn);// 释放

	std::cout << "C 函数获取的返回值: ";
	std::cout << result << std::endl;

	
}

int TestTransferDict(PyObject *pmodule,char*name,int age)
{
	
	PyObject *  pFunc = PyObject_GetAttrString(pmodule, "TestDict");
	if (!pFunc)
	{
		Py_ErrorAndExit("加载TestDict函数失败");
	}

	// 创建字典类型变量
	PyObject *pDict = PyDict_New();  
	PyDict_SetItemString(pDict, "Name", Py_BuildValue("s", name)); //往字典类型变量中填充数据 
	PyDict_SetItemString(pDict, "Age", Py_BuildValue("i", age));     //往字典类型变量中填充数据 

	// 把要输入的字典转为元组参数
	PyObject *pArgs = PyTuple_New(1); // 输入为1个字典
	PyTuple_SetItem(pArgs, 0, pDict); //0---序号  将字典类型变量添加到参数元组中
	
	// 调用函数
	PyObject *pReturn = NULL;
	pReturn = PyEval_CallObject(pFunc, pArgs);
	Py_DECREF(pFunc);// 释放
	Py_DECREF(pArgs);
	
	// 处理返回值
	char *newName = "";
	int newAge = 0;
	int size = PyDict_Size(pReturn);
	std::cout << "返回字典的大小为: " << size << std::endl;
	
	/*PyObject *pReturn_keys = PyDict_Keys(pReturn);
	for (int i = 0;i < size;++i)
	{
		PyObject *key = PyList_GetItem(pReturn_keys, i);
		PyObject *value = PyDict_GetItem(pReturn, key);
	}*/

	// 推荐这种方式
	PyObject *key = 0;
	PyObject *value = 0;
	key = Py_BuildValue("s", "Name");
	if (PyDict_Contains(pReturn, key))
	{
		value = PyDict_GetItem(pReturn, key);
		PyArg_Parse(value, "s", &newName);
	}
	key = Py_BuildValue("s", "Age");
	if (PyDict_Contains(pReturn, key))
	{
		value = PyDict_GetItem(pReturn, key);
		PyArg_Parse(value, "i", &newAge);
	}

	// 也可以使用这种方式
	//PyObject *pNewName = PyDict_GetItemString(pReturn, "Name");
	//PyObject *pNewAge = PyDict_GetItemString(pReturn, "Age");
	//PyArg_Parse(pNewName, "s", &newName);
	//PyArg_Parse(pNewAge, "i", &newAge);

	Py_DECREF(pReturn);// 释放

	std::cout << "C 函数获取的返回值: ";
	std::cout << "{Name: " << newName <<", Age: "<< newAge <<" }"<< std::endl;
	// 结束
}

int TestClass(PyObject *pmodule)
{
	PyObject * pClass = NULL, *pDict = NULL;
	//获取模块字典属性
	pDict = PyModule_GetDict(pmodule);
	// 通过字典属性获取模块中的类 
	pClass = PyDict_GetItemString(pDict, "Person");
	Py_DECREF(pDict);
	if (!pClass)
	{
		Py_ErrorAndExit("获取模块中的类失败");
	}

	// 实例化获取的类
	PyObject *pInstance = PyInstanceMethod_New(pClass);
	if (!pInstance)
	{
		Py_ErrorAndExit("");
	}
	
	//调用类的方法
	PyObject *result = PyObject_CallMethod(pInstance, "greet", "(O, s)", pInstance, "hao hao");
	if (!result)
	{
		Py_ErrorAndExit("");
	}

	Py_DECREF(pClass);
	Py_DECREF(pInstance);
	Py_DECREF(result);
}

 

三、运行结果

/______测试调用HelloWorld______/
py_print>>Hello world!
C 函数获取的返回值: return>>Hello world!
/____________________________/

/______测试调用ADD__5 + 7______/
py_print>> run 5 + 7
C 函数获取的返回值: 12
/____________________________/

/______测试调用TestDict______/
py_print>>input: {'Name': 'casmi', 'Age': 18}
返回字典的大小为: 2
C 函数获取的返回值: {Name: casmi, Age: 100 }
/____________________________/

/______测试调用TestClass______/
py_print>> 我是 chaoen hu, 欢迎 hao hao 来到CASMI.
/____________________________/

请按任意键继续. . .

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值