c++调用python
文章目录
本文是用C++语言对python脚本进行调用
开发环境
电脑有NVIDIA GPU
Anaconda
pycharm
python3.12
Visual Studio 2019
1. 环境配置
1.1 python环境搭建
pytorch环境搭建见博文安装Pytorch(GPU)
1.1.1 python安装路径
如果是按本文推荐的方法进行的环境搭建,创建虚拟环境的时候就下载了python,没有指定安装路径的话,那么python的安装路径在Anaconda安装路径里,如下
C:\Users\PC\anaconda3\envs\u-net

1.1.2 python头文件
Python.h在include文件夹里
C:\Users\PC\anaconda3\envs\u-net\include
1.1.3 python库文件
.lib库文件在libs文件夹里
C:\Users\PC\anaconda3\envs\u-net\libs
1.2 visual studio 2019
1.2.1 添加系统环境变量
将 Python 安装目录添加到系统 PATH 环境变量,将以下两个路径添加到系统环境变量里,添加的详细步骤可参考Windows10_visual studio 2019+opencv 4.5.2里的2.1 添加系统环境变量
C:\Users\PC\anaconda3\envs\u-net
C:\Users\PC\anaconda3\envs\u-net\Scripts
1.2.2 配置属性页
为方便属性用于别的项目,可以直接为项目配置属性表,将前面python头文件路径放在包含目录里,python库文件放在库目录里,将python3.lib和python312.lib添加到依赖项里
配置属性表的详细步骤可参考Windows10_visual studio 2019+opencv 4.5.2里的2.2 在visual studio 2019里配置属性
C:\Users\PC\anaconda3\envs\u-net\include
C:\Users\PC\anaconda3\envs\u-net\libs


1.2.3 验证环境
在VS项目里新建代码文件main.cpp,代码如下
#include <Python.h>
int main()
{
Py_Initialize(); // 初始化
PyRun_SimpleString("print('hello python')");
Py_Finalize(); // 释放资源
return 0;
}
若环境搭建没有问题,此代码文件运行是没问题的,运行结果如下
2. C++调用python函数
在VS项目里创建script文件夹,python脚本放在此文件夹里
2.1 C++ 调用 python 函数
2.1.1 无参
无参函数调用流程:
- 初始化python接口(Py_Initialize)
- 初始化python系统文件路径(PyRun_SimpleString)
- 调用python文件名(PyImport_ImportModule)
- 获取函数对象(PyObject_GetAttrString)
- 调用函数对象(PyObject_CallObject)
- 结束python接口调用,释放资源(Py_Finalize)
script/test1.py
def say():
print("hello python,这是test1")
修改main.cpp代码
#include <iostream>
#include <Python.h>
int main()
{
// 1、初始化python接口
Py_Initialize();
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./../script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test1");
if (module == nullptr)
{
std::cout <<"module not found: test1" << std::endl;
return 1;
}
// 4、获取函数对象
PyObject* func = PyObject_GetAttrString(module, "say");
if (!func || !PyCallable_Check(func))
{
std::cout <<"function not found: say" << std::endl;
return 1;
}
// 5、调用函数
PyObject_CallObject(func, nullptr);
// 6、结束python接口初始化
Py_Finalize();
return 0;
}
运行结果如下
2.1.2 有参
无参函数调用流程:
- 初始化python接口(Py_Initialize)
- 初始化python系统文件路径(PyRun_SimpleString)
- 调用python文件名(PyImport_ImportModule)
- 获取函数对象(PyObject_GetAttrString)
- 传递参数(PyTuple_New,Py_BuildValue)
- 调用函数对象(PyObject_CallObject)
- 接收函数返回值(PyArg_Parse)
- 结束python接口初始化(Py_Finalize)
script/test2.py
def add(a, b):
c = a + b
print(f"{a} + {b} = {c}")
return c
修改main.cpp代码
#include <iostream>
#include <Python.h>
int main()
{
// 1、初始化python接口
Py_Initialize();
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./../script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test2");
if (module == nullptr)
{
std::cout <<"module not found: test2" << std::endl;
return 1;
}
// 4、调用函数
PyObject* func = PyObject_GetAttrString(module, "add");
if (!func || !PyCallable_Check(func))
{
std::cout <<"function not found: add" << std::endl;
return 1;
}
// 5、给 python 传递参数
// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数
// 如果函数中只有一个参数时,写1就可以了
PyObject* args = PyTuple_New(2);
// 0:第一个参数,传入 int 类型的值 1
PyTuple_SetItem(args, 0, Py_BuildValue("i", 1));
// 1:第二个参数,传入 int 类型的值 2
PyTuple_SetItem(args, 1, Py_BuildValue("i", 2));
// 6、使用C++的python接口调用该函数
PyObject* ret = PyObject_CallObject(func, args);
// 7、接收python计算好的返回值
int result;
// i表示转换成int型变量。
// 在这里,最需要注意的是:PyArg_Parse的最后一个参数,必须加上“&”符号
PyArg_Parse(ret, "i", &result);
std::cout << "return is " << result << std::endl;
// 8、结束python接口初始化
Py_Finalize();
return 0;
}
运行结果如下
2.1.3 类
无参函数调用流程:
- 初始化python接口(Py_Initialize)
- 初始化python系统文件路径(PyRun_SimpleString)
- 调用python文件名(PyImport_ImportModule)
- 获取类(PyObject_GetAttrString)
- 根据类构造函数实例化对象(PyEval_CallObject)
- 获取实例的函数对象(PyObject_GetAttrString)
- 传递参数(PyTuple_New,Py_BuildValue)
- 调用函数对象(PyObject_CallObject)
- 接收函数返回值(PyArg_Parse)
- 结束python接口初始化(Py_Finalize)
script/test3.py
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def foo(self):
print(f"my name is {self.name}, my age is {self.age}")
修改main.cpp代码
#include <iostream>
#include <Python.h>
int main()
{
// 1、初始化python接口
Py_Initialize();
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./../script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test3");
if (module == nullptr)
{
std::cout <<"module not found: test3" << std::endl;
return 1;
}
// 4、获取类
PyObject* cls = PyObject_GetAttrString(module, "Person");
if (!cls)
{
std::cout <<"class not found: Person" << std::endl;
return 1;
}
// 5、给类构造函数传递参数
// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数
// 如果函数中只有一个参数时,写1就可以了
PyObject* args = PyTuple_New(2);
// 0:第一个参数,传入字符串类型的值
PyTuple_SetItem(args, 0, Py_BuildValue("s", "jack"));
// 1:第二个参数,传入 int 类型的值
PyTuple_SetItem(args, 1, Py_BuildValue("i", 18));
// 6、根据类名实例化对象
//PyObject* obj = PyEval_CallObject(cls, args);
PyObject* obj = PyObject_CallObject(cls, args);
// 7、根据对象得到成员函数
PyObject* func = PyObject_GetAttrString(obj, "foo");
if (!func || !PyCallable_Check(func))
{
std::cout <<"function not found: foo" << std::endl;
return 1;
}
// 8、使用C++的python接口调用该函数
PyObject_CallObject(func, nullptr);
// 9、结束python接口初始化
Py_Finalize();
return 0;
}
运行结果如下
常见错误
python初始化失败
ModuleNotFoundError
Fatal Python error: init fs encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named ’ encodings’
Current thread Ox0000500c (most recent cal1 first):no Python frame>

解决方案:
Python解释器已经启动,但它找不到自己的标准库
尽管目标是使用 u-net 虚拟环境,但从这个输出来看,C++程序实际上加载并初始化的是你的 Anaconda 基础(base)环境
以下方法可以依次尝试
方法一:移动环境变量位置
在系统环境变量那里,将用的虚拟环境的路径移动至Anaconda前
方法二:指定Python环境的路径
在方法一无用时,可直接指定Python环境的路径
- 验证环境代码
#include <iostream>
#include <Python.h>
int main()
{
// --- 使用 Python 3.8+ 的新初始化 API ---
PyConfig config;
PyConfig_InitPythonConfig(&config);
// 明确设置 Python Home 路径到 u-net 虚拟环境
// 这是解决问题的关键!
PyStatus status = PyConfig_SetString(&config, &config.home, L"C:\\Users\\PC\\anaconda3\\envs\\u-net");
if (PyStatus_Exception(status)) {
// 如果设置失败,这是致命的,必须终止
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to set Python home to the u-net environment.");
return 1;
}
// 使用我们精确配置好的信息来初始化 Python
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
// 如果初始化失败,也是致命的
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to initialize Python from config.");
return 1;
}
// 初始化完成后,清理配置对象
PyConfig_Clear(&config);
// --- 初始化完成 ---
// 运行Python代码
// PyRun_SimpleString 会自动处理打印,不需要再用 std::cout
int result = PyRun_SimpleString("print('--- hello python ---')");
// 检查 PyRun_SimpleString 是否执行成功
if (result != 0) {
std::cout << "Error executing Python code." << std::endl;
// 如果Python代码出错,打印出详细的错误信息
PyErr_Print();
}
// 释放资源
Py_Finalize();
return 0;
}
- C++ 调用 python 函数(无参)
#include <iostream>
#include <Python.h>
int main()
{
// --- 使用 Python 3.8+ 的新初始化 API ---
PyConfig config;
PyConfig_InitPythonConfig(&config);
// 明确设置 Python Home 路径到你的 u-net 虚拟环境
PyStatus status = PyConfig_SetString(&config, &config.home, L"C:\\Users\\PC\\anaconda3\\envs\\u-net");
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to set Python home to the u-net environment.");
return 1;
}
// 使用我们精确配置好的信息来初始化 Python
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to initialize Python from config.");
return 1;
}
// 初始化完成后,清理配置对象
PyConfig_Clear(&config);
// --- 初始化完成 ---
// 检查初始化是否真的成功
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('C:\\\\Users\\\\PC\\\\Desktop\\\\SMY_dll\\\\script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test1");
if (module == nullptr)
{
PyErr_Print(); // 打印详细的Python导入错误
std::cout << "module not found: test1" << std::endl;
return 1;
}
// 4、获取函数对象
PyObject* func = PyObject_GetAttrString(module, "say");
if (!func || !PyCallable_Check(func))
{
PyErr_Print(); // 打印详细的Python属性错误
std::cout << "function not found: say" << std::endl;
Py_DECREF(module); // 释放模块
return 1;
}
// 5、调用函数
PyObject* pRet = PyObject_CallObject(func, nullptr);
if (pRet == nullptr) {
PyErr_Print(); // 如果函数执行出错,打印错误
}
// 6、释放所有Python对象引用
Py_XDECREF(pRet);
Py_DECREF(func);
Py_DECREF(module);
// 7、结束python接口初始化
Py_Finalize();
return 0;
}
- C++ 调用 python 函数(有参)
#include <iostream>
#include <Python.h>
int main()
{
// --- 使用 Python 3.8+ 的新初始化 API ---
PyConfig config;
PyConfig_InitPythonConfig(&config);
// 明确设置 Python Home 路径到你的 u-net 虚拟环境
PyStatus status = PyConfig_SetString(&config, &config.home, L"C:\\Users\\PC\\anaconda3\\envs\\u-net");
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to set Python home to the u-net environment.");
return 1;
}
// 使用我们精确配置好的信息来初始化 Python
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to initialize Python from config.");
return 1;
}
// 初始化完成后,清理配置对象
PyConfig_Clear(&config);
// --- 初始化完成 ---
// 检查初始化是否真的成功
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('C:\\\\Users\\\\PC\\\\Desktop\\\\SMY_dll\\\\script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test2");
if (module == nullptr)
{
std::cout << "module not found: test2" << std::endl;
return 1;
}
// 4、调用函数
PyObject* func = PyObject_GetAttrString(module, "add");
if (!func || !PyCallable_Check(func))
{
std::cout << "function not found: add" << std::endl;
return 1;
}
// 5、给 python 传递参数
// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数
// 如果函数中只有一个参数时,写1就可以了
PyObject* args = PyTuple_New(2);
// 0:第一个参数,传入 int 类型的值 1
PyTuple_SetItem(args, 0, Py_BuildValue("i", 1));
// 1:第二个参数,传入 int 类型的值 2
PyTuple_SetItem(args, 1, Py_BuildValue("i", 2));
// 6、使用C++的python接口调用该函数
PyObject* ret = PyObject_CallObject(func, args);
// 7、接收python计算好的返回值
int result;
// i表示转换成int型变量。
// 在这里,最需要注意的是:PyArg_Parse的最后一个参数,必须加上“&”符号
PyArg_Parse(ret, "i", &result);
std::cout << "return is " << result << std::endl;
// 8、结束python接口初始化
Py_Finalize();
return 0;
}
- C++ 调用 python 类
#include <iostream>
#include <Python.h>
int main()
{
// --- 使用 Python 3.8+ 的新初始化 API ---
PyConfig config;
PyConfig_InitPythonConfig(&config);
// 明确设置 Python Home 路径到你的 u-net 虚拟环境
PyStatus status = PyConfig_SetString(&config, &config.home, L"C:\\Users\\PC\\anaconda3\\envs\\u-net");
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to set Python home to the u-net environment.");
return 1;
}
// 使用我们精确配置好的信息来初始化 Python
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
PyConfig_Clear(&config);
Py_FatalError("Error: Failed to initialize Python from config.");
return 1;
}
// 初始化完成后,清理配置对象
PyConfig_Clear(&config);
// --- 初始化完成 ---
// 检查初始化是否真的成功
if (!Py_IsInitialized())
{
std::cout << "python init failed" << std::endl;
return 1;
}
// 2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('C:\\\\Users\\\\PC\\\\Desktop\\\\SMY_dll\\\\script')");
// 3、调用python文件名,不用写后缀
PyObject* module = PyImport_ImportModule("test3");
if (module == nullptr)
{
std::cout << "module not found: test3" << std::endl;
return 1;
}
// 4、获取类
PyObject* cls = PyObject_GetAttrString(module, "Person");
if (!cls)
{
std::cout << "class not found: Person" << std::endl;
return 1;
}
// 5、给类构造函数传递参数
// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数
// 如果函数中只有一个参数时,写1就可以了
PyObject* args = PyTuple_New(2);
// 0:第一个参数,传入字符串类型的值
PyTuple_SetItem(args, 0, Py_BuildValue("s", "jack"));
// 1:第二个参数,传入 int 类型的值
PyTuple_SetItem(args, 1, Py_BuildValue("i", 18));
// 6、根据类名实例化对象
PyObject* obj = PyObject_CallObject(cls, args);
// 7、根据对象得到成员函数
PyObject* func = PyObject_GetAttrString(obj, "foo");
if (!func || !PyCallable_Check(func))
{
std::cout << "function not found: foo" << std::endl;
return 1;
}
// 8、使用C++的python接口调用该函数
PyObject_CallObject(func, nullptr);
// 9、结束python接口初始化
Py_Finalize();
return 0;
}
方法三:复制python动态链接
用方法二验证环境时没有问题,但是调用 python 函数时出错,显示python init failed
代码A(简单打印)成功了:这证明 PyConfig 初始化代码块本身是正确的。它能够成功地找到 u-net 环境,并初始化Python解释器
代码B(导入模块)失败了:它失败在了 if (!Py_IsInitialized()) 这一步,输出了 “python init failed”
项目可能发生编译时与运行时的Python环境不匹配
解决方案:统一项目配置
步骤1:检查配置属性,检查包含目录、库目录以及附加依赖项(使用绝对路径)是否正确,
步骤2:为彻底杜绝 PATH 环境变量带来的干扰,将python动态链接复制在C++程序生成的可执行文件(.exe)所在的目录
1)复制虚拟环境里的python3.dll和python312.dll文件
2)粘贴至C++项目文件的x64\Release或x64\Debug文件夹下
找不到python函数
ModuleNotFoundError: No module named test1
module not found: test1
使用绝对路径
PyRun_SimpleString("sys.path.append('C:\\\\Users\\\\PC\\\\Desktop\\\\SMY_dll\\\\script')");
参考文章
c++ 调用 python:https://www.bilibili.com/video/BV15m4y187af/
中级篇 – C++ 调用 Python 脚本:http://ai.feishu.cn/docx/VJ0hdyhWUofyw0xutfYcS1OGnvf
更多推荐




所有评论(0)