1、情景
假设有一个Python函数check_data,它返回一个布尔值和两个字典:
# example.py
def check_data():
result = True
dict1 = {"name": "Alice", "age": 30}
dict2 = {"city": "Springfield", "zip": "12345"}
return result, dict1, dict2
在C++中调用这个Python函数,并解析返回的布尔值和两个字典:
#include <Python.h>
#include <iostream>
#include <string>
// 函数声明
void print_dict(PyObject* pDict);
int main() {
// 1. 初始化Python解释器
Py_Initialize();
// 2. 导入Python模块
PyObject *pName = PyUnicode_DecodeFSDefault("example"); // example.py的模块名
PyObject *pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != nullptr) {
// 3. 获取要调用的函数
PyObject *pFunc = PyObject_GetAttrString(pModule, "check_data");
if (pFunc && PyCallable_Check(pFunc)) {
// 4. 调用Python函数并获取返回值
PyObject *pValue = PyObject_CallObject(pFunc, nullptr);
if (pValue != nullptr && PyTuple_Check(pValue)) {
// 5. 解析返回的布尔值和两个字典
if (PyTuple_Size(pValue) == 3) {
// 获取布尔值
PyObject *pBool = PyTuple_GetItem(pValue, 0);
bool result = PyObject_IsTrue(pBool);
std::cout << "Boolean result: " << (result ? "True" : "False") << std::endl;
// 获取并解析第一个字典
PyObject *pDict1 = PyTuple_GetItem(pValue, 1);
if (PyDict_Check(pDict1)) {
std::cout << "Dictionary 1:" << std::endl;
print_dict(pDict1);
}
// 获取并解析第二个字典
PyObject *pDict2 = PyTuple_GetItem(pValue, 2);
if (PyDict_Check(pDict2)) {
std::cout << "Dictionary 2:" << std::endl;
print_dict(pDict2);
}
} else {
std::cerr << "Unexpected tuple size" << std::endl;
}
Py_DECREF(pValue);
} else {
PyErr_Print(); // 打印错误信息
}
} else {
PyErr_Print(); // 打印错误信息
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
} else {
PyErr_Print(); // 打印错误信息
}
// 6. 关闭Python解释器
Py_Finalize();
return 0;
}
// 解析和打印字典内容
void print_dict(PyObject* pDict) {
if (PyDict_Check(pDict)) {
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(pDict, &pos, &key, &value)) {
std::string keyStr = PyUnicode_AsUTF8(key);
if (PyUnicode_Check(value)) {
std::cout << keyStr << ": " << PyUnicode_AsUTF8(value) << std::endl;
} else if (PyLong_Check(value)) {
std::cout << keyStr << ": " << PyLong_AsLong(value) << std::endl;
} else if (PyFloat_Check(value)) {
std::cout << keyStr << ": " << PyFloat_AsDouble(value) << std::endl;
} else if (PyDict_Check(value)) {
std::cout << keyStr << ": {" << std::endl;
print_dict(value);
std::cout << "}" << std::endl;
} else if (PyBool_Check(value)) {
std::cout << keyStr << ": " << (PyObject_IsTrue(value) ? "True" : "False") << std::endl;
} else {
std::cout << keyStr << ": (unhandled type)" << std::endl;
}
}
}
}
2、代码解释
2.1 初始化和关闭Python解释器
Py_Initialize()
和 Py_Finalize()
用于启动和关闭Python解释器。
2.2 导入Python模块
使用 PyUnicode_DecodeFSDefault
将模块名称从C字符串转换为Python字符串。
PyImport_Import
导入指定的Python模块 (example.py)。
2.3 获取并调用Python函数
PyObject_GetAttrString 获取Python模块中的函数对象。
PyObject_CallObject 调用Python函数,不需要参数时传入 nullptr。
2.4 解析Python返回的元组
PyTuple_Check
确认返回的对象是一个元组。
使用 PyTuple_GetItem
分别获取元组中的布尔值和两个字典。
2.5 处理布尔值
PyObject_IsTrue
用于将Python布尔值转换为C++中的布尔类型。
2.6 解析字典
使用 PyDict_Check
确认返回的对象是一个字典。
print_dict
函数递归解析字典的键值对,并打印出来。
2.7 错误处理
使用 PyErr_Print
输出详细的错误信息,帮助调试。