Skip to content

Tuple from iterable #4126

Description

@kevinhartman

I frequently find myself writing code like this to efficiently build a tuple from an iterable:

fn as_tuple(py: Python<'_>, seq: &Bound<PyAny>) -> PyResult<Py<PyTuple>> {
    if seq.is_instance_of::<PyTuple>() {
        Ok(seq.downcast_exact::<PyTuple>()?.into_py(py))
    } else if seq.is_instance_of::<PyList>() {
        let seq = seq.downcast_exact::<PyList>()?;
        Ok(seq.to_tuple().unbind())
    } else {
        // New tuple from iterable.
        Ok(PyTuple::new_bound(
            py,
            seq.iter()?
                .map(|o| Ok(o?.unbind()))
                .collect::<PyResult<Vec<PyObject>>>()?,
        )
        .unbind())
    }
}

Is there a better way to do this? As I understand it, downcasting should be faster if seq is actually already a tuple (calling tuple() on something in CPython is a no-op I believe if the thing is already a tuple, and I'd like those semantics here.

(FWIW, I realize this code could probably be even faster if I were to skip the is_instance_of check and instead handle the PyResult returned from downcast_exact.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions