PyO3 将 rust 结构转换为 &PyAny
PyO3 convert rust struct to &PyAny
我有一个结构
#[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
}
}
问题是,我怎样才能从期望 PyResult<&'py PyAny>
的函数中 return 标记为 pyclass
的 Rust 结构
我想这是你想要 return 的 tensor
。
如果你的 return 类型是 PyResult<DynMat>
你可以 return 然后让自动转换开始。但我假设取决于你是否有标量或张量return 不同类型。
所以,现在您有 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();
但是看看你的代码,还有一件事让我感到困惑:
为了对张量取幂,您需要可变地借用它。在我看来,这表明求幂将 到位 。那你为什么还需要 return 它呢?
或者这是对原始张量的引用?在那种情况下,我会摆脱变量阴影,这样你就可以 return PyRefMut<DynMat>
,你可以通过 from
或 [= 将其转换为 &PyAny
19=].
但实际上,tensor.exp()?
似乎是 return 类型 DynMat
的自有值,所以看起来 new 张量是毕竟创造了。在那种情况下,是的,您需要使用上面显示的 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
我有一个结构
#[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
}
}
问题是,我怎样才能从期望 PyResult<&'py PyAny>
pyclass
的 Rust 结构
我想这是你想要 return 的 tensor
。
如果你的 return 类型是 PyResult<DynMat>
你可以 return 然后让自动转换开始。但我假设取决于你是否有标量或张量return 不同类型。
所以,现在您有 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();
但是看看你的代码,还有一件事让我感到困惑:
为了对张量取幂,您需要可变地借用它。在我看来,这表明求幂将 到位 。那你为什么还需要 return 它呢?
或者这是对原始张量的引用?在那种情况下,我会摆脱变量阴影,这样你就可以 return PyRefMut<DynMat>
,你可以通过 from
或 [= 将其转换为 &PyAny
19=].
但实际上,tensor.exp()?
似乎是 return 类型 DynMat
的自有值,所以看起来 new 张量是毕竟创造了。在那种情况下,是的,您需要使用上面显示的 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