如何在Rust中迭代pyo3 PyObject?

db2dz4w8  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(150)

我有一个预先导入的模块,我用python gil调用了一个方法,如下所示。

Python::with_gil(|py| {
    let res = module.call_method1(py, "my_method", (arg1, arg2))?;
})

这将返回rust对象PyObject,但它返回的是python list。我想迭代此列表,将内部转换为我可以在Rust中使用的内容(这是一个Numpy数组的python列表,我使用的是numpy/ndarray crates)。
我有点搞不清楚应该如何迭代,如果我尝试将cast_as转换为PyList,我会得到警告:UnsafeCell<PyObject> cannot be shared between threads safely.看起来extract也不起作用。
我如何迭代这个PyObject?谢谢。

编辑:按要求添加更多详细信息

如果你使用python类型系统,python返回的值是List[numpy.ndarray]。由于每个numpy数组的长度可能不同,我不能在python中将其全部转换为numpy数组并传递它。下面是一个示例输出:

[array([214.17725372, 192.78236675, 354.27965546, 389.84558392,
          0.99999297])]

我在《 rust 》中尝试过:

  • let pylist = res.cast_as::<PyList>(py)?;

无法编译:UnsafeCell<PyObject> cannot be shared between threads safely .

  • let pylist = res.extract::<PyList>(py)?;

无法编译:the trait 'PyClass' is not implemented for 'PyList'。请注意,我在顶部有use pyo3::prelude::*;

  • let pyany = res.extract::<Vec<PyArray1<f64>>>(py)?;

无法编译:the trait bound 'Vec<PyArray<f64, Dim<[usize; 1]>>>: pyo3::FromPyObject<'_>' is not satisfied。此PyArray来自numpy机箱。

brgchamk

brgchamk1#

我看到你返回了一个包含dtype=floatnumpy数组列表。如果你愿意使用另一个依赖项,在Rust中有rust-numpy,它可以让你将numpy数组Map到ndarrays
ndarrays有一个.to_vec()方法可以转换为标准Rust容器。
在您的情况下,您可以执行以下操作(未进行测试):

use numpy::PyArray1;
use pyo3::{types::IntoPyDict, PyResult, Python};

Python::with_gil(|py| {
    let res: Vec<&PyArray1<f32>> = module // <-- Notice the return type
                                 .call_method1(py, "my_method", (arg1, arg2))?
                                 .extract()?; // <--  Notice the extract
})

Python和Rust类型之间的Map可以在here中找到,然后你可以使用res来做进一步的计算。

println!("I just got a numpy array from python {:?}", res[0]);
println!("I converted that to a vector here: {:?}", res[0].to_vec());

相关问题