深度学习相关的算法,都是使用python语言编写;
应用工程等基本由c++编写;想要将两者很好的结合起来,会缩短开发时间。

实际过程中,会把python的脚本编写成类的形式。然后使用C++对python类进行实例化、实例对象的成员函数调用。

1 环境配置

电脑环境:windows10、vs2015、python3.6
【python3.6】

  • 安装anaconda,使用conda创建虚拟环境,并在虚拟环境中配置好自己需要的资源。
  • 找到安装anaconda路径下,创建的虚拟环境的文件夹,我的电脑在默认的路径下【C:\Users\XXX\Anaconda3\envs】。其中 XXX是自己的电脑的名字。
  • 将自己的虚拟环境拷贝,到创建的VS工程下。

【vs2015】

  • 【新建】–>【项目】–>【Visual C++】–>【空项目】–>【修改工程位置和名称】–>【确定】.
  • 将前面说的python的环境拷贝到该工程下。我的虚拟环境命名为 Pyhton_env。
  • 在工程属性中配置。我的工程名为 Project1。
    C/C++: $(SolutionDir)Project1\Python_env\include
    链接器: $(SolutionDir)\Project1\Python_env\libs\python36.lib
    dll:   将 Python_env/python36.dll 拷贝到工程路径下。

2 代码编写

2.1 方式一

2.1.1 python脚本的编写

一定要确保,python脚本能够正确的运行通 !!!

class Student():
   def __init__(self):
       print("初始化Student成功============================")

   def SetName(self, name="test1"):
       print("进入Student.SetName成功=======================")

       print("参数:name = " + name)
       self._name = name
       print("成功完成操作:self._name = " + self._name)

   def PrintName(self):
       print("进入Student.PrintName成功=====================")
       print("self._name = " + self._name)

def hello():
   print("进入 hello 函数成功=====================")
   print("Hello World")

def world(name):
   print("进入 world 函数成功=====================")
   print("name")

2.1.2 C++脚本的编写

类的实例化

  • 1 打开 python脚本
    pModule = PyImport_ImportModule("test1013")
  • 2 获取 模块属性字典: 也就是将python脚本中的定义的类、函数等存入到pDict
    pDict = PyModule_GetDict(pModule);
  • 3 根据类名 获取类
    pClass = PyDict_GetItemString(pDict, "Student");
  • 4 获取 类的构造函数
    pConstruct = PyInstanceMethod_New(pClass);
  • 5 类的实例
    pInstance = PyObject_CallObject(pConstruct, NULL);

【类的调用】

  • PyObject_CallMethod(pInstance, "SetName", "s", "1111");
#include <Python.h>
#include <iostream>
#include <string>
#include <windows.h> 

int main() {
	// 添加的python的整个完成的环境包的路劲,必须添加。
	Py_SetPythonHome(L"Python_env");

	// 进行初始化
	Py_Initialize();
	if (Py_IsInitialized())
		std::cout << "Init Success" << std::endl;

	PyRun_SimpleString("import sys");             // 在python初始化之后
	PyRun_SimpleString("sys.path.append('./')");   // ""里面填写的是python的语言,添加根路径
	PyRun_SimpleString("print(sys.version)\n");

	PyObject * pModule = NULL;
	PyObject * pDict = NULL; 
	PyObject * pFunc = NULL; 
	PyObject * pClass = NULL;
	PyObject * pConstruct = NULL;
	PyObject * pInstance = NULL;

	//这里是要调用的文件名
	pModule = PyImport_ImportModule("test1013");

	//加载文件中的函数名、类名
	pDict = PyModule_GetDict(pModule);
	if (!pDict)
	{
		printf("Cant find dictionary./n");
	}
    // 调用类==============================
   {
	    // 根据类名获取该类
	     pClass = PyDict_GetItemString(pDict, "Student");
    	if (!pClass) {
		    printf("Can't find Student class.\n");
		    return -1;
    	}

	    // 得到类的构造函数
    	pConstruct = PyInstanceMethod_New(pClass);    //python3的
       	if (!pConstruct) {
	    	printf("Can't create Student instance.\n");
		    return -1;
    	}
	    // 类的实例化
	    pInstance = PyObject_CallObject(pConstruct, NULL);

	    PyObject_CallMethod(pInstance, "SetName", "s", "1111");
	    PyObject_CallMethod(pInstance, "PrintName", NULL, NULL);
    }

   	//函数 并执行 ==================================
	{
	
		pFunc = PyObject_GetAttrString(pModule, "hello");
		//调用函数
		PyEval_CallObject(pFunc, NULL);
		Py_DECREF(pFunc);

		pFunc = PyObject_GetAttrString(pModule, "world");
		PyObject_CallFunction(pFunc, "s", "zhengji");
		Py_DECREF(pFunc);
	}

	//调用Py_Finalize,这个根Py_Initialize相对应的。
	Py_Finalize();

	return 0;

}
 运行结果为:

mfc 调用python脚本 c++如何调用python脚本_Python

注意:

PyObject_CallObject

的使用,在针对类、函数是不同的用法

  • 类中使用:是对类进行实例化,并不是运行类的函数
  • 函数中使用:赋予入参,运行函数
2.1.3 传参的方式

在最后补充

2.2 方式二

2.2.1 调用方式

方式一中调用python里函数,如果python工程较为复杂,就会在python工程中调用其他的python脚本时,出现问题(如找不到、报错、不运行等)。
推荐:如果调用的Python工程,可以一次性全部跑完,就可以用system("python ...") 的方式调用,会更加便捷。

import argparseparser = argparse.ArgumentParser(description='manual to this script')
parser.add_argument("--function", type=str, default="0")
parser.add_argument("--name", type=str, default="0")
args = parser.parse_args()


def hellow():
   print("进入 hello 函数成功=====================")
   print("Hello World")

def world(name):
   print("进入 world 函数成功=====================")
   print("name")
   
if (args.function=="hellow"):
   hellow()
else:
   world(args.name)
 
#include <Python.h>#include <iostream>
#include <string>
#include <windows.h> 

int main() {
	// 添加的python的整个完成的环境包的路劲,必须添加。
	Py_SetPythonHome(L"Python_env");

	// 进行初始化
	Py_Initialize();
	if (Py_IsInitialized())
		std::cout << "Init Success" << std::endl;

	PyRun_SimpleString("import sys");             // 在python初始化之后
	PyRun_SimpleString("sys.path.append('./')");   // ""里面填写的是python的语言,添加根路径
	PyRun_SimpleString("print(sys.version)\n");

	system("python test1013.py --function==world --name==1111");
	system("python test1013.py --function==hellow");
	Py_Finalize();

	return 0;

}

2.2.2 可能出现问题

当在VS中可正常运行工程,当把该工程打包好,被其他的工程再次进行调用发现,找不到深度学习环境,尝试了很多方法后发现:去除系统环境变量中的python环境,然后将该工程要使用的环境进行系统环境变量设置即可。(也许会有更优的方式,有网友清楚望告知)

补充

从 C++ 向 python 传参之前,需要做类型转换。转为 PyObject* 才能传入 python。

  • 例如:
    C++的 int 是一个整数,该值占用 8bytes(64位)的存储空间,而一个 python 的 int 实际是一个 PyObject* 指向 24bytes。
    前 8个bytes是整数,代表引用次数;中间 8bytes是指向 int 类型定义的指针,最后 8bytes是才是这个 int 的值。
    所以 C++ 和 Python 之间参数互相传递都需要 Python提供的 api。

假设函数 func 的输入变量有三个,分别为 一个整数(i),一个浮点数(f),一个字符串(s)

PyObject* args = PyTuple_New(3);
PyObject* arg1 = Py_BuildValue("i",100);  //整数参数
PyObject* arg2 = Py_BuildValue("f", 3.14);  //浮点数参数
PyObject* arg3 = Py_BuildValue("s", "hellow"); //字符串参数

PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 0, arg2);
PyTuple_SetItem(args, 0, arg3);

// 以上的函数可简化为
// PyObject* args = Py_BuildValue("ifs", 100, 3.14, "hellow");

......

 PyObject *pFunc = PyObject_GetAttrString(pModule, "func");
 PyEval_CallObject(pFunc, args );
 Py_DECREF(pFunc);
等价于
......

 PyObject *pFunc = PyObject_GetAttrString(pModule, "func");
 PyObject_CallFunction(pFunc, "ifs", 100,  3.14, "hellow");
 Py_DECREF(pFunc);