@@ -67,23 +67,39 @@ impl PyList {
6767 self . len ( ) == 0
6868 }
6969
70- /// Gets the item at the specified index.
71- ///
72- /// Panics if the index is out of range.
73- pub fn get_item ( & self , index : isize ) -> & PyAny {
74- assert ! ( index >= 0 && index < self . len( ) as isize ) ;
70+ /// Gets the list item at the specified index.
71+ /// # Example
72+ /// ```
73+ /// use pyo3::{prelude::*, types::PyList};
74+ /// Python::with_gil(|py| {
75+ /// let list = PyList::new(py, &[2, 3, 5, 7]);
76+ /// let obj = list.get_item(0);
77+ /// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
78+ /// });
79+ /// ```
80+ pub fn get_item ( & self , index : usize ) -> PyResult < & PyAny > {
7581 unsafe {
76- #[ cfg( not( Py_LIMITED_API ) ) ]
77- let ptr = ffi:: PyList_GET_ITEM ( self . as_ptr ( ) , index as Py_ssize_t ) ;
78- #[ cfg( Py_LIMITED_API ) ]
79- let ptr = ffi:: PyList_GetItem ( self . as_ptr ( ) , index as Py_ssize_t ) ;
80-
82+ let item = ffi:: PyList_GetItem ( self . as_ptr ( ) , index as Py_ssize_t ) ;
8183 // PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
82- ffi:: Py_INCREF ( ptr ) ;
83- self . py ( ) . from_owned_ptr ( ptr )
84+ ffi:: Py_XINCREF ( item ) ;
85+ self . py ( ) . from_owned_ptr_or_err ( item )
8486 }
8587 }
8688
89+ /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
90+ ///
91+ /// # Safety
92+ ///
93+ /// Caller must verify that the index is within the bounds of the list.
94+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
95+ #[ cfg_attr( docsrs, doc( cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ) ) ]
96+ pub unsafe fn get_item_unchecked ( & self , index : usize ) -> & PyAny {
97+ let item = ffi:: PyList_GET_ITEM ( self . as_ptr ( ) , index as Py_ssize_t ) ;
98+ // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
99+ ffi:: Py_XINCREF ( item) ;
100+ self . py ( ) . from_owned_ptr ( item)
101+ }
102+
87103 /// Takes the slice `self[low:high]` and returns it as a new list.
88104 ///
89105 /// Indices must be nonnegative, and out-of-range indices are clipped to
@@ -164,16 +180,19 @@ impl PyList {
164180/// Used by `PyList::iter()`.
165181pub struct PyListIterator < ' a > {
166182 list : & ' a PyList ,
167- index : isize ,
183+ index : usize ,
168184}
169185
170186impl < ' a > Iterator for PyListIterator < ' a > {
171187 type Item = & ' a PyAny ;
172188
173189 #[ inline]
174190 fn next ( & mut self ) -> Option < & ' a PyAny > {
175- if self . index < self . list . len ( ) as isize {
176- let item = self . list . get_item ( self . index ) ;
191+ if self . index < self . list . len ( ) {
192+ #[ cfg( any( Py_LIMITED_API , PyPy ) ) ]
193+ let item = self . list . get_item ( self . index ) . expect ( "tuple.get failed" ) ;
194+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
195+ let item = unsafe { self . list . get_item_unchecked ( self . index ) } ;
177196 self . index += 1 ;
178197 Some ( item)
179198 } else {
@@ -186,8 +205,8 @@ impl<'a> Iterator for PyListIterator<'a> {
186205 let len = self . list . len ( ) ;
187206
188207 (
189- len. saturating_sub ( self . index as usize ) ,
190- Some ( len. saturating_sub ( self . index as usize ) ) ,
208+ len. saturating_sub ( self . index ) ,
209+ Some ( len. saturating_sub ( self . index ) ) ,
191210 )
192211 }
193212}
@@ -238,10 +257,10 @@ mod tests {
238257 fn test_new ( ) {
239258 Python :: with_gil ( |py| {
240259 let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
241- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
242- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
243- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
244- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
260+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
261+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
262+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
263+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
245264 } ) ;
246265 }
247266
@@ -257,19 +276,10 @@ mod tests {
257276 fn test_get_item ( ) {
258277 Python :: with_gil ( |py| {
259278 let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
260- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
261- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
262- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
263- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
264- } ) ;
265- }
266-
267- #[ test]
268- #[ should_panic]
269- fn test_get_item_invalid ( ) {
270- Python :: with_gil ( |py| {
271- let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
272- list. get_item ( -1 ) ;
279+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
280+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
281+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
282+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
273283 } ) ;
274284 }
275285
@@ -290,9 +300,9 @@ mod tests {
290300 let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
291301 let val = 42i32 . to_object ( py) ;
292302 let val2 = 42i32 . to_object ( py) ;
293- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
303+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
294304 list. set_item ( 0 , val) . unwrap ( ) ;
295- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
305+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
296306 assert ! ( list. set_item( 10 , val2) . is_err( ) ) ;
297307 } ) ;
298308 }
@@ -322,13 +332,13 @@ mod tests {
322332 let val = 42i32 . to_object ( py) ;
323333 let val2 = 43i32 . to_object ( py) ;
324334 assert_eq ! ( 4 , list. len( ) ) ;
325- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
335+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
326336 list. insert ( 0 , val) . unwrap ( ) ;
327337 list. insert ( 1000 , val2) . unwrap ( ) ;
328338 assert_eq ! ( 6 , list. len( ) ) ;
329- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
330- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
331- assert_eq ! ( 43 , list. get_item( 5 ) . extract:: <i32 >( ) . unwrap( ) ) ;
339+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
340+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
341+ assert_eq ! ( 43 , list. get_item( 5 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
332342 } ) ;
333343 }
334344
@@ -353,8 +363,8 @@ mod tests {
353363 Python :: with_gil ( |py| {
354364 let list = PyList :: new ( py, & [ 2 ] ) ;
355365 list. append ( 3 ) . unwrap ( ) ;
356- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
357- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
366+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
367+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
358368 } ) ;
359369 }
360370
@@ -431,15 +441,15 @@ mod tests {
431441 Python :: with_gil ( |py| {
432442 let v = vec ! [ 7 , 3 , 2 , 5 ] ;
433443 let list = PyList :: new ( py, & v) ;
434- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
435- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
436- assert_eq ! ( 2 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
437- assert_eq ! ( 5 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
444+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
445+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
446+ assert_eq ! ( 2 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
447+ assert_eq ! ( 5 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
438448 list. sort ( ) . unwrap ( ) ;
439- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
440- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
441- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
442- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
449+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
450+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
451+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
452+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
443453 } ) ;
444454 }
445455
@@ -448,15 +458,15 @@ mod tests {
448458 Python :: with_gil ( |py| {
449459 let v = vec ! [ 2 , 3 , 5 , 7 ] ;
450460 let list = PyList :: new ( py, & v) ;
451- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
452- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
453- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
454- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
461+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
462+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
463+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
464+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
455465 list. reverse ( ) . unwrap ( ) ;
456- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
457- assert_eq ! ( 5 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
458- assert_eq ! ( 3 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
459- assert_eq ! ( 2 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
466+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
467+ assert_eq ! ( 5 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
468+ assert_eq ! ( 3 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
469+ assert_eq ! ( 2 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
460470 } ) ;
461471 }
462472
@@ -465,8 +475,40 @@ mod tests {
465475 Python :: with_gil ( |py| {
466476 let array: PyObject = [ 1 , 2 ] . into_py ( py) ;
467477 let list = <PyList as PyTryFrom >:: try_from ( array. as_ref ( py) ) . unwrap ( ) ;
468- assert_eq ! ( 1 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
469- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
478+ assert_eq ! ( 1 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
479+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
480+ } ) ;
481+ }
482+
483+ #[ test]
484+ fn test_list_get_item_invalid_index ( ) {
485+ Python :: with_gil ( |py| {
486+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
487+ let obj = list. get_item ( 5 ) ;
488+ assert ! ( obj. is_err( ) ) ;
489+ assert_eq ! (
490+ obj. unwrap_err( ) . to_string( ) ,
491+ "IndexError: list index out of range"
492+ ) ;
493+ } ) ;
494+ }
495+
496+ #[ test]
497+ fn test_list_get_item_sanity ( ) {
498+ Python :: with_gil ( |py| {
499+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
500+ let obj = list. get_item ( 0 ) ;
501+ assert_eq ! ( obj. unwrap( ) . extract:: <i32 >( ) . unwrap( ) , 2 ) ;
502+ } ) ;
503+ }
504+
505+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
506+ #[ test]
507+ fn test_list_get_item_unchecked_sanity ( ) {
508+ Python :: with_gil ( |py| {
509+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
510+ let obj = unsafe { list. get_item_unchecked ( 0 ) } ;
511+ assert_eq ! ( obj. extract:: <i32 >( ) . unwrap( ) , 2 ) ;
470512 } ) ;
471513 }
472514}
0 commit comments