目录
- 前言:
- 配置环境:
- 基础夯实:
- 1. 初始化Python解释器
- 2. 导入Python模块
- 3. 获取函数对象
- 4. 调用Python函数
- 5. 处理返回值
- 6. 错误处理
- 7. 资源管理
- 8. 编译和链接
- 9. 线程安全性
- 10. 进一步学习
- 效果展示:
- 实现功能:
- 操作步骤(保姆级教程)
- 第一步打开VS2022
- 第二步配置项目python环境
- 1.添加头文件
- 2.添加库文件
- 3.验证配置正确性。
- 第三步写一个简单的python文件(写的位置易错,需要重点注意)
- 第四步再VS中添加c++调用python的代码:
- 参考资料:
前言:
接上一篇python调用c++动态链接库,环境是VS2022和vscode2023
在python中有许多好用的库,比如numpy,opencv,如果你想在c/c++中调用,你就需要进行混合编程。混合编程涉及到了传递参数,接受参数。不同语言的参数还需要使用一个公共的变量进行计算。
配置环境:
编译器:VS2022,vscode2023
python版本:python3.9.6
基础夯实:
在C++中调用Python库是一个强大的功能,它允许你结合两种语言的优势:C++的性能和效率,以及Python的丰富库和易用性。要实现这一点,你通常需要使用Python的C API,即Python.h头文件中定义的函数和宏。以下是一些基础知识,帮助你开始在C++中调用Python库。
1. 初始化Python解释器
在任何Python API调用之前,你必须首先初始化Python解释器。这通常通过调用Py_Initialize()
函数来完成。在程序的最后,你应该调用Py_Finalize()
来清理Python解释器。
#include <Python.h>
int main() {
Py_Initialize();
// 你的Python代码调用
Py_Finalize();
return 0;
}
2. 导入Python模块
要使用Python库中的函数,你首先需要导入相应的Python模块。这可以通过PyImport_Import()
函数完成,它返回一个表示模块的PyObject指针。
PyObject* pModule = PyImport_Import(PyUnicode_FromString("module_name"));
if (!pModule) {
// 处理错误
}
3. 获取函数对象
一旦导入了模块,你就可以从中获取函数对象了。使用PyObject_GetAttrString()
函数,你可以通过函数名获取到函数对象。
PyObject* pFunc = PyObject_GetAttrString(pModule, "function_name");
if (!pFunc || !PyCallable_Check(pFunc)) {
// 处理错误
}
4. 调用Python函数
要调用Python函数,你需要创建一个包含所有参数的元组,并使用PyObject_CallObject()
函数。
PyObject* pArgs = PyTuple_New(arg_count); // arg_count是参数的数量
// 设置元组中的参数值
// 例如:PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", value));
PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
// 检查pValue是否为NULL来处理可能的错误
5. 处理返回值
Python函数的返回值也是一个PyObject指针。你可以根据返回值的类型使用相应的Python API函数来提取值。
if (pValue) {
// 例如,如果返回值是一个整数,你可以使用PyLong_AsLong()
long result = PyLong_AsLong(pValue);
Py_DECREF(pValue); // 不要忘记释放pValue
}
6. 错误处理
在调用Python API时,错误处理是非常重要的。Python API函数通常会返回一个NULL指针来表示错误。你应该检查每个返回值,并在出现错误时适当地处理它。
if (!some_python_function()) {
// 处理错误,例如使用PyErr_Print()打印错误信息
}
7. 资源管理
在使用Python API时,你会创建很多PyObject对象。为了避免内存泄漏,你应该在不再需要这些对象时调用Py_DECREF()
来释放它们。
8. 编译和链接
要编译包含Python API调用的C++代码,你需要确保链接了Python库。这通常意味着在编译命令中添加-lpythonX.Y
标志,其中X.Y
是你使用的Python版本号。
9. 线程安全性
如果你在多线程环境中使用Python,你需要注意Python的全局解释器锁(GIL)。在调用任何Python API函数之前,你必须确保持有GIL。
10. 进一步学习
Python的C API是非常强大和灵活的,但也可能相当复杂。除了官方文档之外,还有很多教程和示例代码可以帮助你学习如何在C++中调用Python代码。
通过掌握这些基础知识,你就可以开始在C++项目中集成Python库了。随着经验的积累,你将能够更熟练地处理复杂的集成场景。
效果展示:
实现功能:
实现c++调用python函数,传递参数并进行返回值的接收的效果。
操作步骤(保姆级教程)
第一步打开VS2022
// Project1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
system("pause");
}
第二步配置项目python环境
配置的步骤大致分为两部:
1.VS的项目属性>>配置属性>>C/C++>>添加包含目录中
2.VS的项目属性>>配置属性>>链接器>>附件库目录
3.验证环境安装正确性:
1.添加头文件
1.VS的项目属性>>配置属性>>C/C++>>添加包含目录中
C:\Users\wangningning\AppData\Local\Programs\Python\Python39\include
最后不要忘记点击确定,确定之后又回到属性界面。相当于把如下文件添加进去:
2.添加库文件
VS的项目属性>>配置属性>>链接器>>附件库目录>>(参考路径)
C:\Users\wangningning\AppData\Local\Programs\Python\Python39\libs
点击确定之后点击应用。
3.验证配置正确性。
实验代码:
#include <iostream>
#include <Python.h>
第三步写一个简单的python文件(写的位置易错,需要重点注意)
注意(易出现错误),尽量和我的操作一致。
将代码填写进去,文件名是fun.py
#fun.py
import numpy as np
def fun1(x,y):
print("fun1 called with x=",x," and y=",y)
return x+y
python环境中没有装numpy的去装一个,直接再vscode的命令行里面输入
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
第四步再VS中添加c++调用python的代码:
#include <iostream>
#include <Python.h>
// 使用标准命名空间
using namespace std;
int main() {
Py_Initialize(); // 初始化python解释器
if (!Py_IsInitialized()) {
cerr << "Python interpreter initialization failed." << endl;
return -1;
}
PyObject* pName, * pModule, * pFunc, * pArgs; // 定义python对象
pName = PyUnicode_FromString("fun"); // 模块名应该是fun,因为文件名是fun.py
pModule = PyImport_Import(pName); // 载入fun模块
if (!pModule) {
cerr << "Can't find fun.py" << endl;
Py_DECREF(pName);
Py_Finalize();
return -1;
}
// 获取函数对象
pFunc = PyObject_GetAttrString(pModule, "fun1"); // 要调用的函数是fun1
if (!pFunc || !PyCallable_Check(pFunc)) {
cerr << "Cannot find function 'fun1'" << endl;
Py_DECREF(pName);
Py_DECREF(pModule);
Py_Finalize();
return -1;
}
// 准备调用fun1函数,它需要两个参数
pArgs = PyTuple_New(2); // 创建一个元组,长度为2
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 5)); // 将第一个参数设置为整数5
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 10)); // 将第二个参数设置为整数10
// 调用fun1函数
PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
if (pValue != nullptr) {
// 处理返回值(如果需要)
cout << "Function returned: " << PyLong_AsLong(pValue) << endl;
Py_DECREF(pValue);
}
else {
cerr << "Function call failed." << endl;
}
// 销毁python相关对象
Py_DECREF(pName);
Py_DECREF(pModule);
Py_DECREF(pArgs);
Py_DECREF(pFunc);
Py_Finalize();
system("pause"); // 等待用户输入
return 0;
}
我们发现c++成功调用了python的代码,对c++传递的参数进行计算,同时c++对于python返回的结果进行接收。本人也是在技术中学习,欢迎指正文章中的问题,共同进步。
参考资料:
https://zhuanlan.zhihu.com/p/146659551