在C++中使用Python/C API调用Python代码中类中的方法

1 篇文章 0 订阅
1 篇文章 0 订阅

在C++中使用Python/C API调用Python代码中类中的方法,并传递C++定义的数据结构,然后解析复杂的字典值,这个过程涉及多个步骤。以下是一个完整的流程和代码示例。

示例背景

假设我们有一个Python类Person,它包含一个方法get_info,该方法返回一个包含个人信息的复杂字典。C++代码需要将自定义的数据结构传递给这个Python方法,并解析返回的复杂字典。

Python代码 (example.py)

# example.py
class Person:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def get_info(self):
        return {
            "name": self.name,
            "age": self.age,
            "address": {
                "street": self.address["street"],
                "city": self.address["city"],
                "zip": self.address["zip"]
            },
            "hobbies": ["reading", "cycling"],
            "is_student": self.age < 25
        }

C++代码示例
在C++中调用Python类的方法,并解析其返回的复杂字典:

#include <Python.h>
#include <iostream>
#include <string>
#include <map>

// C++定义的地址结构
struct Address {
    std::string street;
    std::string city;
    std::string zip;
};

// 函数声明
void print_dict(PyObject* pDict);
void print_list(PyObject* pList);

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 *pClass = PyObject_GetAttrString(pModule, "Person");

        if (pClass && PyCallable_Check(pClass)) {
            // 4. 创建类的实例
            Address address = {"123 Maple Street", "Springfield", "12345"};

            // 创建Python的字典对象表示C++的地址结构
            PyObject *pAddress = PyDict_New();
            PyDict_SetItemString(pAddress, "street", PyUnicode_FromString(address.street.c_str()));
            PyDict_SetItemString(pAddress, "city", PyUnicode_FromString(address.city.c_str()));
            PyDict_SetItemString(pAddress, "zip", PyUnicode_FromString(address.zip.c_str()));

            // 传递参数 (name, age, address)
            PyObject *pArgs = PyTuple_Pack(3, 
                                           PyUnicode_FromString("Alice"), 
                                           PyLong_FromLong(22), 
                                           pAddress);

            // 调用构造函数创建实例
            PyObject *pInstance = PyObject_CallObject(pClass, pArgs);
            Py_DECREF(pArgs);

            if (pInstance != nullptr) {
                // 5. 调用类中的方法get_info
                PyObject *pResult = PyObject_CallMethod(pInstance, "get_info", nullptr);

                if (pResult != nullptr && PyDict_Check(pResult)) {
                    // 6. 解析返回的复杂字典
                    print_dict(pResult);
                    Py_DECREF(pResult);
                } else {
                    PyErr_Print();  // 打印错误信息
                }

                Py_DECREF(pInstance);
            } else {
                PyErr_Print();  // 打印错误信息
            }
        } else {
            PyErr_Print();  // 打印错误信息
        }

        Py_XDECREF(pClass);
        Py_DECREF(pModule);
    } else {
        PyErr_Print();  // 打印错误信息
    }

    // 7. 关闭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 (PyList_Check(value)) {
                std::cout << keyStr << ": [";
                print_list(value);
                std::cout << "]" << 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;
            }
        }
    }
}

// 解析和打印列表内容
void print_list(PyObject* pList) {
    if (PyList_Check(pList)) {
        Py_ssize_t size = PyList_Size(pList);
        for (Py_ssize_t i = 0; i < size; ++i) {
            PyObject *item = PyList_GetItem(pList, i);
            if (PyUnicode_Check(item)) {
                std::cout << PyUnicode_AsUTF8(item);
            } else if (PyLong_Check(item)) {
                std::cout << PyLong_AsLong(item);
            } else if (PyFloat_Check(item)) {
                std::cout << PyFloat_AsDouble(item);
            } else if (PyDict_Check(item)) {
                std::cout << "{";
                print_dict(item);
                std::cout << "}";
            } else if (PyBool_Check(item)) {
                std::cout << (PyObject_IsTrue(item) ? "True" : "False");
            } else {
                std::cout << "(unhandled type)";
            }
            if (i < size - 1) {
                std::cout << ", ";
            }
        }
    }
}

代码解析

初始化和关闭Python解释器:

Py_Initialize() 启动Python解释器。
Py_Finalize() 关闭Python解释器。

导入Python模块:

PyUnicode_DecodeFSDefault 将模块名称从C字符串转换为Python字符串。
PyImport_Import 导入指定的Python模块 (example.py)。

创建类的实例:

PyObject_GetAttrString 获取Python模块中的类对象 (Person)。
使用 PyDict_New 和 PyDict_SetItemString 创建并填充表示C++结构的Python字典。
PyTuple_Pack 用于将C++字符串、整数、字典等转换为Python对象,并打包成一个元组,作为构造函数的参数。
PyObject_CallObject 调用Python类的构造函数并创建一个实例。
调用类方法并解析返回的复杂字典:

使用 PyObject_CallMethod 调用类中的方法 (get_info)。
print_dict 函数递归解析并打印字典的键值对。
处理不同的数据类型:

使用 PyUnicode_AsUTF8 解析Python字符串。
使用 PyLong_AsLong 解析长整型。
使用 PyFloat_AsDouble 解析浮点数。
PyObject_IsTrue 用于布尔值的判断。
对于嵌套的列表和字典,使用递归解析。

错误处理:

使用 PyErr_Print 输出详细的错误信息,有助于调试。

总结

通过这种方法,可以在C++中调用Python类中的方法,并传递自定义的C++数据结构。同时,也可以解析返回的复杂字典数据结构,处理包含字符串、整数、列表、嵌套字典等各种类型的值。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

平乾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值