Add PyTuple::to_list

This commit is contained in:
David Hewitt 2023-03-12 18:13:08 +00:00
parent 30521c853d
commit 2c11b25fee
3 changed files with 47 additions and 2 deletions

View file

@ -1,7 +1,7 @@
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
use pyo3::prelude::*;
use pyo3::types::{PySequence, PyTuple};
use pyo3::types::{PyList, PySequence, PyTuple};
fn iter_tuple(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
@ -61,6 +61,28 @@ fn sequence_from_tuple(b: &mut Bencher<'_>) {
});
}
fn tuple_new_list(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
let tuple = PyTuple::new(py, 0..LEN);
b.iter(|| {
let _pool = unsafe { py.new_pool() };
let _ = PyList::new(py, tuple);
});
});
}
fn tuple_to_list(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
let tuple = PyTuple::new(py, 0..LEN);
b.iter(|| {
let _pool = unsafe { py.new_pool() };
let _ = tuple.to_list();
});
});
}
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("iter_tuple", iter_tuple);
c.bench_function("tuple_new", tuple_new);
@ -68,6 +90,8 @@ fn criterion_benchmark(c: &mut Criterion) {
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
c.bench_function("tuple_get_item_unchecked", tuple_get_item_unchecked);
c.bench_function("sequence_from_tuple", sequence_from_tuple);
c.bench_function("tuple_new_list", tuple_new_list);
c.bench_function("tuple_to_list", tuple_to_list);
}
criterion_group!(benches, criterion_benchmark);

View file

@ -0,0 +1 @@
Add `PyTuple::to_list()`, as a convenient and efficient conversion from tuples to lists.

View file

@ -6,6 +6,7 @@ use crate::ffi::{self, Py_ssize_t};
#[cfg(feature = "experimental-inspect")]
use crate::inspect::types::TypeInfo;
use crate::internal_tricks::get_ssize_index;
use crate::types::PyList;
use crate::types::PySequence;
use crate::{
exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyObject,
@ -213,6 +214,15 @@ impl PyTuple {
length: self.len(),
}
}
/// Return a new list containing the contents of this tuple; equivalent to the Python expression `list(tuple)`.
///
/// This method is equivalent to `self.as_sequence().list()` and faster than `PyList::new(py, self)`.
pub fn to_list(&self) -> &PyList {
self.as_sequence()
.list()
.expect("failed to convert tuple to list")
}
}
index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice);
@ -444,7 +454,7 @@ tuple_conversion!(
#[cfg(test)]
mod tests {
use crate::types::{PyAny, PyTuple};
use crate::types::{PyAny, PyList, PyTuple};
use crate::{Python, ToPyObject};
use std::collections::HashSet;
@ -918,4 +928,14 @@ mod tests {
"Some destructors did not run"
);
}
#[test]
fn test_tuple_to_list() {
Python::with_gil(|py| {
let tuple = PyTuple::new(py, vec![1, 2, 3]);
let list = tuple.to_list();
let list_expected = PyList::new(py, vec![1, 2, 3]);
assert!(list.eq(list_expected).unwrap());
})
}
}