3

From Python, I want to call a Rust function that returns a Python object:

my_rust_module.my_function()  # => <object>

I am not sure how to create this function since the PYO3 guide on class instantiation describes how to instantiate such an object as a PyRef, however I can't work out how to return such a reference from a pyfunction.

This is what I am trying:

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

However, PyRef does not seem to be a valid return type (compiler says "wrong number of type arguments: expected 1, found 0"), and I don't know how to convert a PyRef into something that can be returned such as a PyObject.

4

1 回答 1

3

Given the proper scaffolding is in place, such as pymodule and pyclass definitions, there are multiple ways to accomplish this:

#[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))
}

Or:

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

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

I also take the liberty of wrapping returned object in PyResult in order to propagate the possible errors to python land. You can unwrap in Rust and return the naked object instead, but I'd argue this way of handling error is recommended.


Edit: the previous answer was not complete and a little bit misleading. The simplest way is actually just:

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

The PYO3 pyclass guide states:

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.

I believe this is only true if the said value doesn't cross Rust / Python boundary. If it does, pyfunction macro automatically converts the Python objects to Rust values and the Rust return value back into a Python object. The PYO3 guide could be more specific here.

于 2019-12-06T06:58:06.973 回答