深度学习相关的算法,都是使用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 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.2 C++ 调用 python
【 类的实例化 】
-
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);
{
//调用python脚本中的函数 并执行
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;
}
运行结果为:
2.3 传参的方式
从 C++ 向 python 传参之前,需要做类型转换。转为 PyObject* 才能传入 python。
例如:
C++的 int 是一个整数,该值占用 8bytes(64位)的存储空间,而一个 python 的 int 实际是一个 PyObject* 指向 24bytes。
前 8个bytes是整数,代表引用次数;中间 8bytes是指向 int 类型定义的指针,最后 8bytes是才是这个 int 的值。
所以 C++ 和 Python 之间参数互相传递都需要 Python提供的 api。
假设函数的输入变量有三个,分别为 一个整数(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");