Pieces of Py #5 Slice me up

Posted on Tue 17 September 2019 in Python • 3 min read

In my learnings of Python I came to know that there is something called slicing. Given a sequence that you want to get certain sub-elements from, you can more easily get the results you want with slicing, instead of e.g. making a couple of for-loops.

Lets start with taking a simple list:

my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

If I want to get everything but the first item I can do:

print(my_list[1:]) # Get everything except the first item
[2, 3, 4, 5, 6, 7, 8, 9]

Or if I want only the first item:

print(my_list[:1]) # Get only the first item
[1]

Syntax

The syntax for slicing is:

my_list[start:stop:step]

So if stop is omitted you will get the rest of the list. Step is by default 1 if omitted.

If start is omitted it starts from the first item on the list.

print(my_list[2:]) # Get everything except the first two items
print(my_list[:2]) # Get the first two items
[3, 4, 5, 6, 7, 8, 9]
[1, 2]

Using negative parameters in slicing

If we put negative numbers for start or stop, it starts counting from the end of the list instead of the beginning, as can be seen in the following example:

print(my_list[-1:]) # Get only the last item
print(my_list[:-1]) # Get everything except the last item
[9]
[1, 2, 3, 4, 5, 6, 7, 8]

How does start and stop really work?

Next example was a bit confusing for me. When assigning a start value higher than 1 and a stop value less than the length of the list.

print(my_list) # print the list again for reference
print(my_list[2:4])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 4]

I thought the positions are 0-based, so to get the number 3 when using 2 as a start parameter was nothing strange, but what about getting 4 when using 4 as the stop parameter? And shouldn't the result contain 3 items?

It turns out that slicing doesn't work on index positions on the items, but rather on a slice position between the items. To illustrate that I found this helpful illustration on Stack Overflow where this was very nicely explained:

#                 +---+---+---+---+---+---+---+---+---+
#                 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
#                 +---+---+---+---+---+---+---+---+---+
# Slice position: 0   1   2   3   4   5   6   7   8   9
# Index position:   0   1   2   3   4   5   6   7   8

When we do my_list[2:4] the start position is 2, which gives the third (0-based) slice position just before number 3 on my_list. So number 3 is included in the result.

The stop position is given as 4, which gives the slice position after the fourth item (4) on my_list.

So the slicing gives us back the item after the start slicing position, up until before the stop slice poistion.

Using negative steps (reversing the list)

We can also use a negative value on the step parameter, with the effect that the list is reversed.

print(my_list[::-1]) # Reverse the list
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Slicing strings

Slicing can be used on strings as well for example.

my_string = "When I find myself in times of trouble"

print(f'Reversed: {my_string[::-1]}')
print(f'Sub-element: {my_string[12:18]}')
Reversed: elbuort fo semit ni flesym dnif I nehW
Sub-element: myself

Conclusion

Python's slicing is a nice way to be able to get sub-elements from e.g. a list, a tuple, a string, or some other sqeuence. At first, it can be a little confusing how the start:stop:step parameters work.

It helps to think of start and stop as positions between the items in the sequence, instead of the actual positions of the items.

Resources

Let me know on Twitter if I can improve this article, or if you have other resources to help out with understanding this topic.