C++调用Python后解析复杂数据结构

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 输出详细的错误信息,帮助调试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平乾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值