You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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"**章节:详细讲解了双向类型转换的规则和示例
  • FromPyObject trait的API文档:核心的Python到Rust类型转换 trait,包含自定义转换的方法
  • PyDict和PyAny的API文档:讲解如何在Rust中操作Python字典、动态判断对象类型

这些内容专门针对Python参数传入Rust的场景,你可以重点查看FromPyObject的派生示例和PyDict的迭代、取值方法。

内容的提问来源于stack exchange,提问作者mike rodent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:17:48