通过pybind11在C++端读取Python端的嵌套字典数据

发布于:2025-04-14 ⋅ 阅读:(38) ⋅ 点赞:(0)

通过pybind11在C++端读取Python端的嵌套字典数据

下面是一个完整的示例程序,展示如何在C++端通过pybind11读取Python端传递的嵌套字典数据。

C++端代码 (pybind11_module.cpp)

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <variant>

namespace py = pybind11;

// 定义可以存储多种类型的variant
using ValueType = std::variant<
    int, 
    float, 
    double, 
    std::string, 
    std::unordered_map<std::string, std::variant<int, float, double, std::string>>
>;

// 递归打印嵌套字典的函数
void print_nested_dict(const std::unordered_map<std::string, ValueType>& dict, const std::string& indent = "") {
    for (const auto& pair : dict) {
        std::cout << indent << pair.first << ": ";
        
        if (std::holds_alternative<int>(pair.second)) {
            std::cout << std::get<int>(pair.second) << " (int)" << std::endl;
        } else if (std::holds_alternative<float>(pair.second)) {
            std::cout << std::get<float>(pair.second) << " (float)" << std::endl;
        } else if (std::holds_alternative<double>(pair.second)) {
            std::cout << std::get<double>(pair.second) << " (double)" << std::endl;
        } else if (std::holds_alternative<std::string>(pair.second)) {
            std::cout << "\"" << std::get<std::string>(pair.second) << "\" (string)" << std::endl;
        } else if (std::holds_alternative<std::unordered_map<std::string, ValueType>>(pair.second)) {
            std::cout << "{" << std::endl;
            print_nested_dict(std::get<std::unordered_map<std::string, ValueType>>(pair.second), indent + "  ");
            std::cout << indent << "}" << std::endl;
        }
    }
}

// 处理Python字典的函数
void process_dict(py::dict py_dict) {
    std::unordered_map<std::string, ValueType> cpp_dict;
    
    // 将Python字典转换为C++字典
    for (auto item : py_dict) {
        std::string key = py::cast<std::string>(item.first);
        py::handle value = item.second;
        
        if (py::isinstance<py::int_>(value)) {
            cpp_dict[key] = py::cast<int>(value);
        } else if (py::isinstance<py::float_>(value)) {
            cpp_dict[key] = py::cast<double>(value);
        } else if (py::isinstance<py::str>(value)) {
            cpp_dict[key] = py::cast<std::string>(value);
        } else if (py::isinstance<py::dict>(value)) {
            // 递归处理嵌套字典
            py::dict nested_py_dict = py::cast<py::dict>(value);
            std::unordered_map<std::string, ValueType> nested_cpp_dict;
            
            for (auto nested_item : nested_py_dict) {
                std::string nested_key = py::cast<std::string>(nested_item.first);
                py::handle nested_value = nested_item.second;
                
                if (py::isinstance<py::int_>(nested_value)) {
                    nested_cpp_dict[nested_key] = py::cast<int>(nested_value);
                } else if (py::isinstance<py::float_>(nested_value)) {
                    nested_cpp_dict[nested_key] = py::cast<double>(nested_value);
                } else if (py::isinstance<py::str>(nested_value)) {
                    nested_cpp_dict[nested_key] = py::cast<std::string>(nested_value);
                } else {
                    throw std::runtime_error("Unsupported nested value type");
                }
            }
            
            cpp_dict[key] = nested_cpp_dict;
        } else {
            throw std::runtime_error("Unsupported value type");
        }
    }
    
    // 打印处理后的字典
    std::cout << "Processed dictionary in C++:" << std::endl;
    print_nested_dict(cpp_dict);
}

PYBIND11_MODULE(nested_dict_example, m) {
    m.doc() = "Example of processing nested Python dictionaries in C++";
    m.def("process_dict", &process_dict, "Process a nested Python dictionary in C++");
}

Python端测试代码 (test.py)

import nested_dict_example

# 创建一个嵌套字典
nested_dict = {
    "name": "John Doe",
    "age": 30,
    "scores": {
        "math": 95.5,
        "english": 88,
        "history": 92.3
    },
    "address": {
        "street": "123 Main St",
        "city": "New York",
        "zip": "10001"
    },
    "is_student": False,
    "height": 175.2
}

# 调用C++函数处理字典
nested_dict_example.process_dict(nested_dict)

CMakeLists.txt (构建配置)

cmake_minimum_required(VERSION 3.4...3.18)
project(nested_dict_example)

# 查找Python和pybind11
find_package(Python REQUIRED COMPONENTS Development)
find_package(pybind11 REQUIRED)

# 创建Python模块
pybind11_add_module(nested_dict_example pybind11_module.cpp)

# 设置C++标准
set_target_properties(nested_dict_example PROPERTIES CXX_STANDARD 17)

编译和运行步骤

  1. 创建构建目录并编译:
mkdir build
cd build
cmake ..
make
  1. 运行Python测试脚本:
python test.py

预期输出

Processed dictionary in C++:
name: "John Doe" (string)
age: 30 (int)
height: 175.2 (double)
is_student: 0 (int)
scores: {
  math: 95.5 (double)
  english: 88 (int)
  history: 92.3 (double)
}
address: {
  street: "123 Main St" (string)
  city: "New York" (string)
  zip: "10001" (string)
}

代码说明

  1. 类型处理:

    • 使用std::variant处理多种可能的字典值类型
    • 支持基本类型(int, float, string)和嵌套字典
  2. 递归处理:

    • 递归地将Python嵌套字典转换为C++的嵌套unordered_map
    • 递归地打印嵌套字典结构
  3. 类型检查:

    • 使用py::isinstance检查Python对象的类型
    • 对不支持的类型抛出异常
  4. 构建系统:

    • 使用CMake和pybind11构建Python扩展模块

这个示例展示了如何完整地在C++端处理Python传递的嵌套字典数据,包括类型转换、递归处理和错误检查。


网站公告

今日签到

点亮在社区的每一天
去签到