【问题标题】:How can I access a Rust Iterator from Python using PyO3?如何使用 PyO3 从 Python 访问 Rust 迭代器?
【发布时间】:2020-05-22 12:37:09
【问题描述】:

我对 Rust 很陌生,我的第一个“严肃”项目涉及使用 PyO3 为小型 Rust 库编写 Python 包装器。这基本上很轻松,但我正在努力研究如何将 Rust Vecs 上的惰性迭代器暴露给 Python 代码。

到目前为止,我一直在收集迭代器产生的值并返回一个列表,这显然不是最好的解决方案。这是一些说明我的问题的代码:

use pyo3::prelude::*;

// The Rust Iterator, from the library I'm wrapping.
pub struct RustIterator<'a> {
    position: usize,
    view: &'a Vec<isize>
}

impl<'a> Iterator for RustIterator<'a> {
    type Item = &'a isize;

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.view.get(self.position);
        if let Some(_) = result { self.position += 1 };
        result
    }
}

// The Rust struct, from the library I'm wrapping.
struct RustStruct {
    v: Vec<isize>
}

impl RustStruct {
    fn iter(&self) -> RustIterator {
        RustIterator{ position: 0, view: &self.v }
    }
}

// The Python wrapper class, which exposes the 
// functions of RustStruct in a Python-friendly way.
#[pyclass]
struct PyClass {
    rust_struct: RustStruct,
}

#[pymethods]
impl PyClass {
    #[new]
    fn new(v: Vec<isize>) -> Self {
        let rust_struct = RustStruct { v };
        Self{ rust_struct }
    }

    // This is what I'm doing so far, which works
    // but doesn't iterate lazily.
    fn iter(&self) -> Vec<isize> {
        let mut output_v = Vec::new();
        for item in self.rust_struct.iter() {
            output_v.push(*item);
        }
        output_v
    }
}

我尝试用 Python 包装器包装 RustIterator 类,但我不能使用 PyO3 的 #[pyclass] proc。带有生命周期参数的宏。我查看了pyo3::types::PyIterator,但这看起来像是从 Rust 访问 Python 迭代器的一种方式,而不是相反的方式。

如何在 Python 中通过 RustStruct.v 访问惰性迭代器?可以安全地假设 Vec 中包含的类型始终派生 CopyClone,并且需要在 Python 端使用一些代码的答案是可以的(但不太理想)。

【问题讨论】:

    标签: python rust iterator pyo3


    【解决方案1】:

    您可以将 RustIterator 设为 pyclass,然后使用 rust iter 本身实现正确的特征 (PyIterProtocol)。

    未测试,但类似:

    #[pyclass]
    pub struct RustIterator<'a> {
        position: usize,
        view: &'a Vec<isize>
    }
    
    impl<'a> Iterator for RustIterator<'a> {
        type Item = &'a isize;
    
        fn next(&mut self) -> Option<Self::Item> {
            let result = self.view.get(self.position);
            if let Some(_) = result { self.position += 1 };
            result
        }
    }
    
    #[pyproto]
    impl PyIterProtocol for Iter {
        fn __next__(mut slf: PyRefMut<Self>) -> IterNextOutput<usize, &'static str> {
            match self.next() {
                Some(value) => IterNextOutput::Yield(value),
                None => IterNextOutput::Return("Ended")
            }
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 2022-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 2016-07-22
      • 2021-07-03
      • 1970-01-01
      相关资源
      最近更新 更多