如何在C++中直接嵌入Python3.11字符串代码并获取返回值?
在C++中嵌入Python 3.11并直接执行字符串源码(获取返回结果)
你可以通过Python C API的PyRun_String配合模块命名空间的方式,直接在内存中执行字符串形式的Python代码,无需写入文件,同时能获取函数返回结果。以下是具体实现方案:
核心思路
- 初始化Python解释器;
- 创建一个模块对象,将字符串形式的Python代码执行到该模块的命名空间中;
- 从模块中提取目标函数(如
main)并调用; - 处理函数返回的结果(如将Python列表转换为C++数组/容器);
- 清理资源并关闭解释器。
完整代码示例
#include <Python.h> #include <vector> #include <cstdio> int main() { // 初始化Python解释器 if (!Py_Initialize()) { fprintf(stderr, "Python解释器初始化失败\n"); return 1; } // 定义内嵌的Python脚本字符串 const char* python_script = R"( def main(): # 返回固定大小的Python列表(对应需求中的数组) return [10, 20, 30, 40, 50] )"; // 创建模块对象(使用__main__作为模块名,也可自定义) PyObject* pModule = PyImport_AddModule("__main__"); if (!pModule) { fprintf(stderr, "创建模块失败\n"); Py_Finalize(); return 1; } // 获取模块的命名空间字典 PyObject* pModuleDict = PyModule_GetDict(pModule); if (!pModuleDict) { fprintf(stderr, "获取模块命名空间失败\n"); Py_DECREF(pModule); Py_Finalize(); return 1; } // 执行Python字符串代码,将内容加载到模块命名空间 PyObject* pExecResult = PyRun_String(python_script, Py_file_input, pModuleDict, pModuleDict); if (!pExecResult) { PyErr_Print(); // 打印Python侧的错误信息 Py_DECREF(pModule); Py_Finalize(); return 1; } Py_DECREF(pExecResult); // 执行脚本的返回值无需保留 // 从模块中获取main函数 PyObject* pMainFunc = PyDict_GetItemString(pModuleDict, "main"); if (!pMainFunc || !PyCallable_Check(pMainFunc)) { fprintf(stderr, "无法获取可调用的main函数\n"); if (PyErr_Occurred()) PyErr_Print(); Py_DECREF(pModule); Py_Finalize(); return 1; } // 调用main函数(无参数传递) PyObject* pFuncResult = PyObject_CallObject(pMainFunc, NULL); if (!pFuncResult) { PyErr_Print(); Py_DECREF(pMainFunc); Py_DECREF(pModule); Py_Finalize(); return 1; } // 将Python列表转换为C++ vector std::vector<int> cpp_array; if (PyList_Check(pFuncResult)) { Py_ssize_t list_size = PyList_Size(pFuncResult); for (Py_ssize_t i = 0; i < list_size; ++i) { PyObject* pItem = PyList_GetItem(pFuncResult, i); if (PyLong_Check(pItem)) { long value = PyLong_AsLong(pItem); cpp_array.push_back(static_cast<int>(value)); } else { fprintf(stderr, "列表元素不是整数类型\n"); Py_DECREF(pFuncResult); Py_DECREF(pMainFunc); Py_DECREF(pModule); Py_Finalize(); return 1; } } } else { fprintf(stderr, "main函数未返回列表类型\n"); Py_DECREF(pFuncResult); Py_DECREF(pMainFunc); Py_DECREF(pModule); Py_Finalize(); return 1; } // 输出转换后的C++数组 printf("从Python main()获取的数组:"); for (int num : cpp_array) { printf("%d ", num); } printf("\n"); // 清理Python对象资源 Py_DECREF(pFuncResult); Py_DECREF(pMainFunc); Py_DECREF(pModule); // 关闭Python解释器 Py_Finalize(); return 0; }
关键注意事项
- Python 3 API适配:你原来的
PyString_FromString是Python 2的API,Python 3中需替换为PyUnicode_FromString; - 引用计数管理:所有通过Python API创建的对象(除了部分借用引用的情况),都需要用
Py_DECREF释放,避免内存泄漏; - 编译链接:编译时需要链接Python库,以Linux为例:
Windows下需配置Python的include和lib路径,链接g++ -o embed_python embed_python.cpp $(python3.11-config --cflags --ldflags)python311.lib; - 参数传递:如果需要给
main函数传参,可改用PyObject_CallFunction或PyObject_CallMethod,例如:// 传递两个整数参数给main PyObject* pArgs = PyTuple_Pack(2, PyLong_FromLong(100), PyLong_FromLong(200)); PyObject* pFuncResult = PyObject_CallObject(pMainFunc, pArgs); Py_DECREF(pArgs);
内容的提问来源于stack exchange,提问作者Krohnus Melavea
相关产品推荐
相关产品推荐

