Why can't a range object be used to index a list?

Issue

In Python 3.9, it is not possible to use a range object to index a list.
Indeed running the following code, the second print will return an error stating "TypeError: list indices must be integers or slices, not range".

x = [1, 2, 3]
s = slice(3)
r = range(3)

print(x[s]) # ok
print(x[r]) # error

Why is this? Couldn’t the Python interpreter just convert the range to a slice under the hood, and use that for indexing?
Is this because of some fundamental reason, or is just something the developer did not implement (yet?)?

Interestingly, it is indeed possible to index numpy arrays using range!

Solution

A slice and range are subtly different things, even though both use a start, stop, step triplet. If Python were to silently use one in place of the other, it could lead to subtle bugs.


To see the difference directly, one can indeed look at numpy where the two cause different indexing:

>>> arr = np.array([0, 1, 2, 3, 4])
>>> arr[slice(1, -1)]
array([1, 2, 3])
>>> arr[range(1, -1)]
array([], dtype=int64)

The result is different because slice and range have different meaning for negative numbers.

  • A range represents a part of the number line of integers. This extends to negative numbers.
  • A slice represents a part of the ordinal numbers/indices of sequences.1 This wraps negative numbers back to positive numbers.

Or put simpler, the meaning of a slice depends on the size of a sequence whereas a range does not. Thus, accidentally using one in place of the other would be wrong.


1 Technically, a slice represents any concept of start, stop, step. The standard sequence types interpret this as numerical indices. It is also possible for a slice to represent the edges of a graph, for example.

Answered By – MisterMiyagi

Answer Checked By – Willingham (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.