如何在Rust的pyfunction中接收并处理Python字典列表?
处理PyO3中Python字典列表到Rust类型的转换问题
1. 已知键值类型时的转换方案
如果明确知道_source里的键和对应值的类型,最直接的方式是用#[derive(FromPyObject)]定义匹配结构的Rust结构体,PyO3会自动完成Python字典到Rust类型的转换:
示例代码:
use pyo3::prelude::*; // 定义匹配_source结构的Rust结构体 #[derive(FromPyObject)] struct SourceData { id: i64, title: String, active: bool, } // 定义每个hit的结构,包含_source字段 #[derive(FromPyObject)] struct HitItem { _source: SourceData, // 其他需要的字段可以添加在这里 } #[pyfunction] fn update_index(path: String, index_name: String, hits: Vec<HitItem>) -> PyResult<()> { // 直接使用转换后的Rust原生类型 for hit in hits { println!("ID: {}, Title: {}, Active: {}", hit._source.id, hit._source.title, hit._source.active); } Ok(()) }
如果_source的键是动态的,但值类型统一(比如全为字符串),可以直接用HashMap<String, String>接收_source:
#[derive(FromPyObject)] struct HitItem { _source: std::collections::HashMap<String, String>, }
转换失败时会自动返回PyResult错误,方便你捕获处理。
2. 未知键值类型时的处理方案
如果_source的键值类型不确定,需要用PyO3提供的Python原生对象类型动态处理:
方案一:直接用PyDict接收
把hits的类型指定为Vec<&PyDict>,直接操作Python字典的API:
use pyo3::types::PyDict; #[pyfunction] fn update_index(path: String, index_name: String, hits: Vec<&PyDict>) -> PyResult<()> { for hit in hits { // 获取_source对应的Python字典 let source = hit.get_item("_source")?.downcast::<PyDict>()?; // 遍历键值对并根据类型处理 for (key, value) in source.iter() { let key_str = key.extract::<String>()?; if value.is_instance_of::<pyo3::types::PyString>() { let val = value.extract::<String>()?; println!("{}: {}", key_str, val); } else if value.is_instance_of::<pyo3::types::PyLong>() { let val = value.extract::<i64>()?; println!("{}: {}", key_str, val); } // 其他类型(如布尔、列表等)可同理判断处理 } } Ok(()) }
方案二:保留PyObject动态转换
如果你坚持用Vec<HashMap<String, PyObject>>接收hits,可以通过downcast方法把_source对应的PyObject转为PyDict:
use pyo3::types::PyDict; #[pyfunction] fn update_index(path: String, index_name: String, hits: Vec<std::collections::HashMap<String, PyObject>>) -> PyResult<()> { for hit in hits { if let Some(source_obj) = hit.get("_source") { // 将PyObject转为PyDict引用 let source_dict = source_obj.downcast::<PyDict>()?; // 后续操作同方案一 for (key, value) in source_dict.iter() { // 处理键值对 } } } Ok(()) }
这种方式灵活性高,但需要手动处理类型判断和转换错误。
相关PyO3文档位置
你需要的Python到Rust类型转换内容,主要集中在这些地方:
- PyO3手册的**"Converting between Rust and Python types"**章节:详细讲解了双向类型转换的规则和示例
FromPyObjecttrait的API文档:核心的Python到Rust类型转换 trait,包含自定义转换的方法PyDict和PyAny的API文档:讲解如何在Rust中操作Python字典、动态判断对象类型
这些内容专门针对Python参数传入Rust的场景,你可以重点查看FromPyObject的派生示例和PyDict的迭代、取值方法。
内容的提问来源于stack exchange,提问作者mike rodent
相关产品推荐
相关产品推荐

