如何使用 PY03 实现 returns 一个 Python 对象的 Rust 函数

How to implement a Rust function that returns a Python object using PY03

从 Python,我想调用一个 return 是 Python 对象的 Rust 函数:

my_rust_module.my_function()  # => <object>

我不确定如何创建此函数,因为 PYO3 guide on class instantiation 描述了如何将此类对象实例化为 PyRef,但是我不知道如何 return pyfunction.

这样的引用

这就是我正在尝试的:

#[pyfunction]
fn my_function(py: Python) -> PyRef {
    let gil = Python::acquire_gil();
    let py = gil.python();
    PyRef::new(py, MyStruct { }).unwrap()
}

但是,PyRef 似乎不是有效的 return 类型(编译器说 "wrong number of type arguments: expected 1, found 0"),我不知道如何转换 PyRef变成可以 returned 的东西,例如 PyObject.

如果有适当的脚手架,例如 pymodulepyclass 定义,有多种方法可以实现此目的:

#[pyfunction]
fn my_function() -> PyResult<PyObject> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let pyref = PyRef::new(py, MyStruct {})?;

    Ok(pyref.to_object(py))
}

或者:

#[pyfunction]
fn my_function() -> PyResult<Py<MyStruct>> {
    let gil = Python::acquire_gil();
    let py = gil.python();

    Py::new(py, MyStruct {})
}

我还冒昧地将 returned 对象包装在 PyResult 中,以便将可能的错误传播到 python 土地。您可以在 Rust 中展开并 return 裸对象,但我认为建议使用这种处理错误的方式。


编辑:之前的回答不完整,有点误导。最简单的方法其实就是:

#[pyfunction]
fn my_function() -> PyResult<MyStruct> {
    Ok(MyStruct {})
}

The PYO3 pyclass guide 状态:

You can use pyclasses like normal rust structs.

However, if instantiated normally, you can't treat pyclasses as Python objects.

To get a Python object which includes pyclass, we have to use some special methods.

我相信只有当上述值不跨越 Rust / Python 边界时,这才是正确的。如果是,pyfunction 宏会自动将 Python 对象转换为 Rust 值,并将 Rust return 值转换回 Python 对象。 PYO3 指南在这里可以更具体。