python语言有着很强大的第三方支持,并且程序简单,易于编写。在一些应用情况,如excel自动化上,C++由于相关的支持库很难找到,所以考虑到调用现成的python库实现相关功能。但题主经过搜索发现这种接口制作的相关资料比较少,因此希望能尽绵薄之力,做一点贡献,希望能够帮助到后来者。过程中难免有些错误,望能体谅指正。
1 环境配置
基本环境:VS2019 + python3.7.6
1.1 安装python
安装过程略了,相关的版本官网上都有,安装过程也是一路点下来就行了。
注意:安装的python要和编译环境保持一致,具体而言就是两点:
— 32位对32位,64位对64位
— 默认的python安装包是具有release库的,但是没有debug库,如果想要debug,需要在安装python的时候多勾选一项
1.2 VS2019的属性配置
主要是几个部分:
VS2019里:
工程属性 >VC++目录>包含目录 填入python安装目录下的include文件夹
工程属性 >VC++目录>库目录 填入python安装目录下的libs文件夹
工程属性 > 链接器 > 输入>附件依赖项 填入python安装目录下的libs文件夹里的lib文件
1.3 调用头文件
在使用的时候需要include一个python.h的头文件
2 调用方法
下面的内容主要转载自https://blog.csdn.net/yangjf91/article/details/93062961
2.1 常用函数:
功能 | 函数 |
---|---|
初始化Python环境 | Py_Initialize() |
添加模块路径(或者说脚本路径) | PyRun_SimpleString() |
导入模块 | PyImport_ImportModule() |
导入函数 | PyObject_GetAttrString() |
使用函数 | PyObject_CallObject() |
获取结果 | PyArg_Parse() |
结束释放 | Py_DECREF()、Py_Finalize() |
2.2 常用指针
PyObject* 这是一个相当常用的指针了。
这个指针能存储任意类型的python变量(包括整型,浮点型,字符串,列表,字典等等),还能存储一些调用的对象,如模块等。
2.3 调用过程
- 初始化Python环境
//< 设置python的路径并初始化运行环境
Py_SetPythonHome(L"E:/python");
Py_Initialize();
//< 定位调用模块路径,便于后面调用模块
PyRun_SimpleString("import sys");
//添加Insert模块路径
PyRun_SimpleString("sys.path.append('D:/pythonfile')");
- 添加导入的模块
//< 接着上面已经定位好的模块路径,直接调用需要的模块(这里是Test模块)
PyObject* pModule = PyImport_ImportModule("Test");
if (pModule == NULL)
{
//< 如果模块调用失败,则返回false
std::cout << "Import Failed!" << std::endl;
return false;
}
- 调用函数
//< 声明两个输入参数
PyObject* Params = PyTuple_New(2);
//< 传入两个python函数的输入参数
PyObject* Param1 = Data;
PyObject* Param2 = Statistics;
//< 封装输入参数
PyTuple_SetItem(Params, 0, Param1);
PyTuple_SetItem(Params, 1, Param2);
//< 调用func函数,并传入参数,FuncRes为函数的返回值
PyObject* PyFunc = PyObject_GetAttrString(pModule, "func");
PyObject* FuncRes = PyEval_CallObject(PyFunc , Params);
- 结果释放
//< 没啥好说的
Py_Finalize();
3 数据转化
介绍几个常用的函数
3.1 C++转python
介绍一个十分好用的函数,Py_BuildValue(),用来将C++的数据转换成python类型的数据,返回一个PyObject的指针,支持字符串,整形,浮点型等类型转化,甚至还能建立python中的列表,字典等。使用方法见下表
命令 | 实际输入 |
---|---|
Py_BuildValue("") | None |
Py_BuildValue(“i”, 123) | 123 |
Py_BuildValue(“iii”, 123, 456, 789) | (123, 456, 789) |
Py_BuildValue(“s”, “hello”) | ‘hello’ |
Py_BuildValue(“ss”, “hello”, “world”) | (‘hello’, ‘world’) |
Py_BuildValue(“s#”, “hello”, 4) | ‘hell’ |
Py_BuildValue("()") | () |
Py_BuildValue("(i)", 123) | (123,) |
Py_BuildValue("(ii)", 123, 456) | (123, 456) |
Py_BuildValue("(i,i)", 123, 456) | (123, 456) |
Py_BuildValue("[i,i]", 123, 456) | [123, 456] |
Py_BuildValue("{s:i,s:i}", “abc”, 123, “def”, 456) | {‘abc’: 123, ‘def’: 456} |
Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) | (((1, 2), (3, 4)), (5, 6)) |
在进行字符串转换时,需要注意两个问题:
1.Py_BuildValue()支持的是char*
2.字符串的编码问题,C++中字符串的默认编码方式是ASCII码,但在python中的编码方式为utf-8编码,因此存在着中文转码的问题。对于存在中文的字符串如CString,推荐使用下面的方法,亲测有效
CString DataCStr = _T("2020-09-17");
DWORD dwNum = WideCharToMultiByte(CP_UTF8, NULL, DataCStr, -1, NULL, NULL, NULL, NULL);
char* Mychar = new char[dwNum];
WideCharToMultiByte(CP_UTF8, NULL, DataCStr, -1, Mychar, dwNum, NULL, NULL);
PyObject* temp = Py_BuildValue("s", Mychar);
3.2 python转C++
通常是读取python模块中的返回值,进而将PyObject*类型转化为对应的C++数据类型。
几个函数(更多的可以百度一下,这部分内容很多)这个太明显了,就不解释了。
long PyLong_AsLong(PyObject *pylong)
double PyFloat_AsDouble(PyObject *pyfloat)
3.3 列表处理
3.3.1 建立列表
PyObject* PyList_New(int)
输入参数: 建立列表的长度
返回值: PyObject类型的指针,指向新创建创建的列表
Tips:如果建立空列表,可以将输入参数置为零
3.3.2 append列表
PyList_Append(PyObject* param1,PyObject* param2)
输入参数:
param1: 原列表
param2: 需要加在列表末尾的内容
3.3.3 获取列表长度
ssize_t PyList_Size(PyObject *)
返回值:列表长度
输入参数:需要获得长度的列表
3.3.4 获取列表中指定位置的数据
(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t)
输入参数:
PyObject * 对应列表
Py_ssize_t 偏移量
返回值:
对应位置的元素
4 目前遇到的几个问题
4.1 Py_Initialize()报错
初始化调用Py_Initialize()就报错,网上关于这个问题都是检查python版本有没有问题,路径是否设置对。最后通过C++调用Python Py_Initialize失败解决了问题,即添加Py_SetPythonHome(L"<Python路径>"),也就是前面的2.2节中“初始化Python环境”中的第一句(实际上,这句有时候不加也是好使的,好使的情况可能是因为设置了环境变量,但是为了保险,还是加上这句)。
4.2 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize
这种情况通常是VS中配置的环境与python中的不符,常见的比如:VS中的编译环境是32位的,而python安装的是64位的。所以,解决办法就是,要么换个python版本,要么配置合适的VS编译环境。
4.3 LNK1104 无法打开文件“python37_d.lib”
这个问题就是你在VS中用了debug版本,但在安装python的时候却没安装debug包,这种问题你只要在安装的时候加入debug包,并在附加依赖项中加入相关的lib文件就行了,debug包勾选如1.1节中的介绍
详细内容参见:https://blog.csdn.net/weixin_43788499/article/details/84933210
5 参考链接
- C++调用Python总结
https://blog.csdn.net/yangjf91/article/details/93062961 - C++调用Python脚本中的函数
https://www.cnblogs.com/betterwgo/p/8176525.html - LNK1104 无法打开文件“python37_d.lib”问题处理
https://blog.csdn.net/weixin_43788499/article/details/84933210 - WideCharToMultiByte 函数使用说明
https://www.cnblogs.com/zhoudingcocng/p/6433960.html - 编码格式介绍
https://blog.csdn.net/byf0521hlyp/article/details/80365045