The Basics of Indexing and Slicing Python Lists (2024)

A guide for beginners, by a beginner

The Basics of Indexing and Slicing Python Lists (1)

I was preparing to demonstrate indexing and slicing lists to a group of fellow Python beginners a few days ago, and I got stuck on what seemed like a couple of pretty basic use cases. So after poking around a bit to get un-stuck, I figured it was worth sharing what I learned.

Accessing the items in a list (and in other iterables like tuples and strings) is a fundamental skill for Python coders, and many Python tools follow similar conventions for indexing and slicing (e.g. numpy Arraysand pandas DataFrames). So it’s worth being familiar with the ins and outs.

“Indexing” means referring to an element of an iterable by its position within the iterable. “Slicing” means getting a subset of elements from an iterable based on their indices.

By way of analogy, I was recently summoned to jury duty, and they assigned each potential juror a number. You might say my juror number was my index. When they said, “Juror number 42; please stand,” I knew they were talking to me. When they said, “Jurors 37 through 48, please report back at 3:30 pm,” that slice of the larger group collectively sighed and went to lunch.

Let’s first create a list we can play around with using a list comprehension:

my_list = [_ for _ in 'abcdefghi']
my_list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

To retrieve an element of the list, we use the index operator ([]):

my_list[0]'a'

Lists are “zero indexed”, so [0] returns the zero-th (i.e. the left-most) item in the list, and [1] returns the one-th item (i.e. one item to the right of the zero-th item). Since there are 9 elements in our list ([0] through [8]), attempting to access my_list[9] throws an IndexError: list index out of range, since it is actually trying to get the tenth element, and there isn’t one.

Python also allows you to index from the end of the list using a negative number, where [-1] returns the last element. This is super-useful since it means you don’t have to programmatically find out the length of the iterable in order to work with elements at the end of it. The indices and reverse indices of my_list are as follows:

 0 1 2 3 4 5 6 7 8
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
-9 -8 -7 -6 -5 -4 -3 -2 -1

A slice is a subset of list elements. In the case of lists, a single slice will always be of contiguous elements. Slice notation takes the form

my_list[start:stop]

where start is the index of the first element to include, and stop is the index of the item to stop at without including it in the slice. So my_list[1:5] returns ['b', 'c', 'd', 'e']:

 0 1 2 3 4 5 6 7 8
× ↓ ↓ ↓ ↓ × × × ×
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

Leaving either slice boundary blank means start from (or go to) the end of the list. For example:

my_list[5:]['f', 'g', 'h', 'i']
my_list[:4]['a', 'b', 'c', 'd']

Using a negative indexer will set the start/stop bounds relative to their position from the end of the list, so my_list[-5:-2] returns ['e', 'f', 'g']:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
× × × × ↑ ↑ ↑ × ×
-9 -8 -7 -6 -5 -4 -3 -2 -1

Note that if you try my_list[-2:-5], you’ll get an empty list. This was something I got tripped up on, but here’s what’s happening: in order to be included in the slice, an element must be at or to the right of the start boundary AND to the left of the stop boundary. Because the -2 is already to the right of -5, the slicer stops before populating any value into the slice.

A for loop works exactly the same way; the first loop below has no output, but the second does:

for i in range(-2,-5):
print(i)
for i in range(-5,-2):
print(i)
-5
-4
-3

The slicer can take an optional third argument, which sets the interval at which elements are included in the slice. So my_list[::2] returns ['a', 'c', 'e', 'g', 'i']:

 0 1 2 3 4 5 6 7 8
×¹² ×¹² ×¹² ×¹²
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

And my_list[1::2] returns ['b', 'd', 'f', 'h']:

 0 1 2 3 4 5 6 7 8
× ×¹² ×¹² ×¹² ×¹
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

Negative step values reverse the direction in which the slicer iterates through the original list:

my_list[::-1]['i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

The indexed positions of list elements don’t change, but the order in which the elements are returned does. The sense of the start and stop boundaries is also reversed, so the start value should be the right-most position in the slice, and the stop value should be to the left of that. So my_list[5:3:-1] gives us [‘f’, ‘e’]:

<----<----<----<----<----<----<----<----<--
0 1 2 3 4 5 6 7 8
× × × × ↓ ↓ × × ×
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

Likewise, my_list[-2:-5:-1] gives us ['h', 'g', 'f']:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
× × × × ×
-9 -8 -7 -6 -5 -4 -3 -2 -1
<----<----<----<----<----<----<----<----<--

And my_list[-1:-8:-3] gives us ['i', 'f', 'c']:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
× ×¹ ³ ײ ×¹ ³ ײ ×¹ ↑
-9 -8 -7 -6 -5 -4 -3 -2 -1
<----<----<----<----<----<----<----<----<--

I hope this saves you some of the confusion I encountered while working through indexing and slicing, especially with negative steps.

The Basics of Indexing and Slicing Python Lists (2024)
Top Articles
Latest Posts
Article information

Author: Fredrick Kertzmann

Last Updated:

Views: 5611

Rating: 4.6 / 5 (66 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Fredrick Kertzmann

Birthday: 2000-04-29

Address: Apt. 203 613 Huels Gateway, Ralphtown, LA 40204

Phone: +2135150832870

Job: Regional Design Producer

Hobby: Nordic skating, Lacemaking, Mountain biking, Rowing, Gardening, Water sports, role-playing games

Introduction: My name is Fredrick Kertzmann, I am a gleaming, encouraging, inexpensive, thankful, tender, quaint, precious person who loves writing and wants to share my knowledge and understanding with you.