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.)
I frequently find myself writing code like this to efficiently build a tuple from an iterable:
Is there a better way to do this? As I understand it, downcasting should be faster if
seqis actually already a tuple (callingtuple()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_ofcheck and instead handle thePyResultreturned fromdowncast_exact.)