首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用PyO3从Python访问Rust Iterator?

如何使用PyO3从Python访问Rust Iterator?
EN

Stack Overflow用户
提问于 2020-05-22 12:37:09
回答 1查看 543关注 0票数 11

我对Rust非常陌生,我的第一个“严肃”项目涉及使用PyO3为一个小型锈蚀库编写Python包装器。这基本上是无痛的,但我很难解决如何将锈蚀Vec上的懒惰迭代器暴露给Python代码。

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

代码语言:javascript
复制
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上编写一些代码的答案是可以的(但不太理想)。

EN

回答 1

Stack Overflow用户

发布于 2021-12-27 15:08:53

您可以使您的RustIterator成为一个pyclass,然后使用锈蚀iter本身实现适当的特性(PyIterProtocol)。

没有经过测试,但类似于:

代码语言:javascript
复制
#[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")
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61955227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档