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

如何从PyO3传递PyList至Polars表达式?编译错误求助

如何将PyList传递给Polars的.over()方法?

我尝试将PyList传递给Polars表达式,想把period_group传入.over()方法,但遭遇编译错误。

初始尝试代码

#[pyfunction]
fn data_bleach(pydf: PyDataFrame, period_group: &Bound<'_, PyList>) -> PyResult<PyDataFrame> {

    let df: DataFrame = pydf.into();
        let df_bleached = df
        .lazy()
        .select([
            when(col("*").over([period_group]).count().gt(5))
            .then(col("*").fill_null(median("*").over(["country", "sector"])))
            .otherwise(col("*").fill_null(mean("*").over(["country", "sector"])))

        ])
        .collect().expect("could not collect"); 
    Ok(PyDataFrame(df_bleached))

}

对应错误

error[E0277]: the trait bound `Expr: From<&pyo3::Bound<'_, PyList>>` is not satisfied
   --> src/lib.rs:20:27
    |
20  |             when(col("*").over([period_group]).count().gt(5))
    |                           ^^^^ the trait `From<&pyo3::Bound<'_, PyList>>` is not implemented for `Expr`, which is required by `&pyo3::Bound<'_, PyList>: Into<Expr>`

尝试转换为Vec后的代码

#[pyfunction]
fn data_bleach(pydf: PyDataFrame, period_group:&Bound<'_, PyList>) -> PyResult<PyDataFrame> {
   
    let list: Vec<String> = pyo3::Bound::extract_bound(&period_group).into_iter()
        .map(|item| item.to_string())
        .collect();


    let df: DataFrame = pydf.into();
        let df_bleached = df
        .lazy()
        .select([
            when(col("*").over(list).count().gt(5))
            .then(col("*").fill_null(median("*").over(["country", "sector"])))
            .otherwise(col("*").fill_null(mean("*").over(["country", "sector"])))

        ])
        .collect().expect("could not collect"); 
    Ok(PyDataFrame(df_bleached))

}

对应错误

error[E0277]: the trait bound `Expr: From<std::string::String>` is not satisfied
   --> src/lib.rs:25:27
    |
25  |             when(col("*").over(list).count().gt(5))
    |                           ^^^^ the trait `From<std::string::String>` is not implemented for `Expr`, which is required by `std::string::String: Into<Expr>`
    |
    = help: the following other types implement trait `From<T>`:
              <Expr as From<bool>>
              <Expr as From<i8>>
              <Expr as From<i16>>
              <Expr as From<i32>>
              <Expr as From<i64>>
              <Expr as From<u32>>
              <Expr as From<u64>>
              <Expr as From<f32>>
            and 3 others
    = note: required for `std::string::String` to implement `Into<Expr>`
note: required by a bound in `polars_plan::dsl::<impl Expr>::over`
   --> /home/bourbon/.cargo/registry/src/index.crates.io-6f17d22bba15001f/polars-plan-0.39.1/src/dsl/mod.rs:908:37
    |
908 |     pub fn over<E: AsRef<[IE]>, IE: Into<Expr> + Clone>(self, partition_by: E) -> Self {
    |                                     ^^^^^^^^^^ required by this bound in `polars_plan::dsl::<impl Expr>::over`

另一种尝试的代码片段

let list: Vec<String> = period_group.extract_bound::<Vec<String>>().into_iter().map(|c| col(&c)).collect::<Vec<_>>();

对应错误

error[E0599]: no method named `extract_bound` found for reference `&pyo3::Bound<'_, PyList>` in the current scope
   --> src/lib.rs:16:42
    |
16  | ...ist: Vec<String> = period_group.extract_bound::<Vec<String>>().into_iter().map(|c| col(&c))...
    |                       -------------^^^^^^^^^^^^^-----------------
    |                       |            |
    |                       |            this is an associated function, not a method
    |                       help: use associated function syntax instead: `pyo3::Bound<'_, PyList>::extract_bound()`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: the candidate is defined in the trait `pyo3::FromPyObject`
   --> /home/bourbon/.cargo/registry/src/index.crates.io-6f17d22bba15001f/pyo3-0.21.2/src/conversion.rs:226:5
    |
226 |     fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/lib.rs:16:90
   |
16 | ...ng>>().into_iter().map(|c| col(&c)).collect::<Vec<_>>();
   |                            ^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = note: all function arguments must have a statically known size

解决方案

问题核心在于.over()方法接收的是可转换为Expr的类型的集合,而非直接的字符串或PyList。需要先把PyList中的字符串提取出来,再转换成Polars的col表达式:

#[pyfunction]
fn data_bleach(pydf: PyDataFrame, period_group: &Bound<'_, PyList>) -> PyResult<PyDataFrame> {
    // 1. 从PyList提取Vec<String>,处理Python转换错误
    let group_cols: Vec<String> = Bound::extract_bound(period_group)?;
    
    // 2. 将每个字符串转换为Polars Expr(列表达式)
    let partition_exprs: Vec<Expr> = group_cols.into_iter().map(|col_name| col(col_name)).collect();

    let df: DataFrame = pydf.into();
    let df_bleached = df
        .lazy()
        .select([
            when(col("*").over(&partition_exprs).count().gt(5))
                .then(col("*").fill_null(median("*").over(["country", "sector"])))
                .otherwise(col("*").fill_null(mean("*").over(["country", "sector"])))
        ])
        .collect()?; // 用?替代expect,规范处理错误
    
    Ok(PyDataFrame(df_bleached))
}

关键修正点

  • 正确使用Bound::extract_bound提取PyList内容,通过?处理可能的转换错误
  • 将提取的字符串逐个转为col()表达式,得到Vec<Expr>,这是.over()能接受的类型
  • 在.over()中传入&partition_exprs,Vec<Expr>实现了AsRef<[Expr]>,符合方法的类型约束
  • 用?替代expect,遵循PyO3错误处理规范,将错误向上传递为PyResult

内容的提问来源于stack exchange,提问作者Trevor Seibert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:32:11