Search code examples
rustpyo3

How to return a PyTuple in rust using pyo3?


I want a function that simply creates and returns a tuple as an example.

Basic template starting code (maturin new) looks like:

use pyo3::prelude::*;

/// Formats the sum of two numbers as string.
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())
}

/// A Python module implemented in Rust.
#[pymodule]
fn tuple(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
    Ok(())
}

I have tried something like this but can't figure out what combination of things is required to even compile.

#[pyfunction]
fn f_ret_tuple() -> PyResult<&'static PyTuple> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let tuple: &PyTuple;
    let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
    tuple = PyTuple::new(py, elements);
    Ok(tuple)
}

Solution

  • The problem is that the compiler can't prove your tuple will not outlive the GIL acquisition. But per the docs,

    In a function or method annotated with #[pyfunction] or #[pymethods] you can declare it as a parameter, and PyO3 will pass in the token when Python code calls it.

    So:

    #[pyfunction]
    fn f_ret_tuple(py: Python<'_>) -> PyResult<&PyTuple> {
        let tuple: &PyTuple;
        let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
        tuple = PyTuple::new(py, elements);
        Ok(tuple)
    }