Slices


Martin McBride, 2021-04-18
Tags slicing step negative index
Categories python language beginning python
In Python language

Slicing allows us to access part of a list or other sequence. In this article we will see how to:

  • Specify a slice of a list.
  • Use negative indices.
  • Delete or replace a slice of a list.
  • Take a slice of a tuple or string.
  • Loop over a slice.
  • Use steps.

Slicing a list

We already know how to obtain a list element by indexing:

k = [10, 20, 30, 40, 50]
print(k[1])    # 20

Of course, k[1] references element number 1 of list k, which is the second element because elements are numbered from 0.

But we can also obtain a portion of the list, using slicing:

k = [10, 20, 30, 40, 50]
m = k[1:4]
print(m)    # [20, 30, 40]

In this case, k[1:4] is a list that contains elements of k from 1 up to but not including 4. In other words, it contains k[1], k[2], and k[3].

Slicing creates a new list that contains a copy of part of the original list.

There are a couple of extra shortcuts that you can use:

k = [10, 20, 30, 40, 50]
p = k[:2]    # [10, 20, 30]
q = k[3:]    # [40, 50]
r = k[:]     # [10, 20, 30, 40, 50]

The slice k[:2] includes elements of k from the start up to but not including element 2. It is equivalent to k[0:2].

The slice k[3:] includes elements of k from the 3 to the end. It is equivalent to k[3:len(k)].

The slice k[:] includes all the elements of k, from the start to the end. It creates a complete new copy of k.

One more thing that is useful to know about slices is that you don't need to worry about going past the end of the list. The slice will just return the elements that exist, it will not give an index error:

k = [10, 20, 30, 40, 50]
x = k[3:8]       # [40, 50]
y = k[:9]        # [10, 20, 30, 40, 50]
z = k[100:200]   # []

In this case, k[3:8] just returns the last two elements of the list (the equivalent of k[3:5]). k[:9] returns the entire list (the equivalent of k[0:5]). And k[100:200] returns and empty list because the whole slice is outside the range of the list.

Using negative indices

Negative indices are a useful feature of lists (and other sequences such as strings or tuples).

Suppose you wanted to index the last element in a list. You can do this:

k = [10, 20, 30, 40, 50]
print(k[len(k)-1])    # 50

But Python provides a handy shortcut. If you use a negative index, it will count back from the end of the list. So k[-1] represents the last element of the list. k[-2] represents the last but one element of the list, and so on:

k = [10, 20, 30, 40, 50]
print(k[-1])    # 50
print(k[-2])    # 40
print(k[-3])    # 30

This is particularly useful in conjunction with slices. For example, suppose you wanted to create a slice containing every element except the last element. You can do this:

print(k[:-1])   # [10, 20, 30, 40]

Or alternatively, the following code slices the last two elements of the list:

print(k[-2:])   # [40, 50]

Of course, you could do either of these things by calculating the length of the list, but negative indices are a lot neater.

Delete or replace a slice of a list

You can delete a slice of a list like this:

k = [10, 20, 30, 40, 50]
del k[2:4]
print(k)     # [10, 20, 50]

You can also replace a section of the list:

k = [10, 20, 30, 40, 50]
k[2:4] = [3, 4]
print(k)     # [10, 20, 3, 4, 50]

This code replaces the slice [2:3] (which contains the elements [30, 40]) with a new section [3, 4].

Notice that these operations change the original list.

Slicing tuples and strings

You can slice a tuple or a string in exactly the same way as a list. For example:

t = (2, 4, 6, 8)
s = 'Hello world!'
print(t[1:3])     # (4, 6)
print(s[6:11])    # 'world'

You cannot delete or replace slices of tuples or strings, because tuples and strings are immutable types.

Loop over a slice

You can loop over a slice:

k = [10, 20, 30, 40, 50]
for n in k[1:4]:
    print(n)

As you might expect, this code loops over the slice [20, 30, 40], and prints out:

20
30
40

Using steps

Slices have an optional third value, the step.

You might have noticed a similarity between slices and the range function used in for loops. They use very similar logic.

Here is an example:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[1:6:2])    # [20, 40, 60]

This code slices from element 1 up to but not including element 6, in steps of 2. So it slices elements 1, 3, and 5, giving the result [20, 40, 60].

Here is another example:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[::3])    # [10, 40, 70]

This slices the entire list in steps of 3. So it slices elements 0, 3 and 6.

One final useful thing is that you can use negative steps (just like you can with the range function). The steps through the list backwards:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[5:2:-1])    # [60, 50, 40]

This steps from element 5 down to but not including element 2. Since we are counting backwards, the start element is greater than the end element.

You can use other step values:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[::-3])    # [90, 60, 30]

This counts from the end of the list down to the start of the list, in steps of 3.

If you found this article useful, you might be interested in the book Python Quick Start or other books by the same author.