2

我有一个结构

#[pyclass]
pub struct DynMat {
   ...
}

我有这个功能

#[pyfunction]
#[text_signature = "(tensor/)"]
pub fn exp<'py>(py: Python<'py>, tensor_or_scalar: &'py PyAny) -> PyResult<&'py PyAny> {
    // I need to return &PyAny because I might either return PyFloat or DynMat
    if let Ok(scalar) = tensor_or_scalar.cast_as::<PyFloat>() {
        let scalar: &PyAny = PyFloat::new(py, scalar.extract::<f64>()?.exp());
        Ok(scalar)
    } else if let Ok(tensor) = tensor_or_scalar.cast_as::<PyCell<DynMat>>() {
        let mut tensor:PyRef<DynMat> = tensor.try_borrow()?;
        let tensor:DynMat = tensor.exp()?;
        // what now? How to return tensor
    }
}

pyclass问题是,我怎样才能从一个期望的函数返回一个标有PyResult<&'py PyAny>

4

1 回答 1

2

我认为这是tensor您想要返回的。

如果您的返回类型是PyResult<DynMat>您可以返回它并让自动转换开始。但我假设根据您是否有标量或张量,您将返回不同的类型。

所以,现在你有tensor一个拥有DynMat,我们需要将它移动到 python 堆。看起来是这样的:

let tensor_as_py = Py::new(py, tensor)?.into_ref(py);
return Ok(tensor_as_py);

PS:您也可以更简洁地编写转换尝试:

pub fn blablabla() {
  let tensor: PyRefMut<DynMat> = tensor_or_scalar.extract();
  if let Ok(tensor) = tensor {
    let tensor = tensor.exp();

但是查看您的代码,还有一件事让我感到困惑:

为了对张量求幂,你是在可变地借用它。这对我来说意味着取幂将到位。那么为什么你还需要退货呢?

或者这是否意味着对原始张量的引用?在这种情况下,我会摆脱变量阴影,这样您就可以返回PyRefMut<DynMat>,您可以将其转换为&PyAnyviafrominto.

但实际上,tensor.exp()?似乎返回了一个拥有的 type 值DynMat,所以似乎毕竟创建了一个新的张量。在这种情况下,是的,您需要使用Py::new上面显示的方法将其从 Rust 移动到 python 堆。

编辑:使用以前的版本as_ref(py)而不是into_ref(py). 前者从对象中借用Py<_>给你一个引用,但后者实际上消耗Py<_>对象。

该文档实际上在这里准确地解释了您的用例https://docs.rs/pyo3/0.13.2/pyo3/prelude/struct.Py.html#method.into_ref

于 2021-06-21T15:46:24.640 回答