How to raise an IndexError when slice indices are out of range?

13,948

Solution 1

In Python 2 you can override __getslice__ method by this way:

class MyList(list):
    def __getslice__(self, i, j):
        len_ = len(self)
        if i > len_ or j > len_:
            raise IndexError('list index out of range')
        return super(MyList, self).__getslice__(i, j)

Then use your class instead of list:

>>> egg = [1, "foo", list()]
>>> egg = MyList(egg)
>>> egg[5:10]
Traceback (most recent call last):
IndexError: list index out of range

Solution 2

There is no silver bullet here; you'll have to test both boundaries:

def slice_out_of_bounds(sequence, start=None, end=None, step=1):
    length = len(sequence)
    if start is None:
        start = 0 if step > 1 else length
    if start < 0:
        start = length - start
    if end is None:
        end = length if step > 1 else 0
    if end < 0:
        end = length - end
    if not (0 <= start < length and 0 <= end <= length):
        raise IndexError()

Since the end value in slicing is exclusive, it is allowed to range up to length.

Share:
13,948
elegent
Author by

elegent

from stuffYouNeedToKnow import atLeastALittleBit you = YourRealYou() while you.doWhatYouLove == ":)": you.loveWhatYouDo()

Updated on June 15, 2022

Comments

  • elegent
    elegent about 2 years

    The Python Documentation states that

    slice indices are silently truncated to fall in the allowed range

    and therefor no IndexErrors are risen when slicing a list, regardless what start or stop parameters are used:

    >>> egg = [1, "foo", list()]
    >>> egg[5:10]
    []
    

    Since the list egg does not contain any indices greater then 2, a egg[5] or egg[10] call would raise an IndexError:

    >> egg[5]
    Traceback (most recent call last):
    IndexError: list index out of range
    

    The question is now, how can we raise an IndexError, when both given slice indices are out of range?

    • Martijn Pieters
      Martijn Pieters almost 9 years
      Why not? Because an empty slice result is still a valid object. If you want to raise exceptions, probe the start and end indices manually, or explicitly test for len(egg) against your boundaries.
    • elegent
      elegent almost 9 years
      @MartijnPieters: Thanks for your reply! I am not sure if this is a duplicate because I ask about "How to raise an IndexError when slice a sequence" and not the "Why slicing index out of range works". But correct me If I am wrong :)
    • Martijn Pieters
      Martijn Pieters almost 9 years
      You asked two questions, making your post too broad. I duped you to a previous question that answers the first, and provided your options to answer the second.
    • elegent
      elegent almost 9 years
      @MartijnPieters: Ok I see, I have a edited my question...
    • Martijn Pieters
      Martijn Pieters almost 9 years
      So when should an exception be raised? When both indices are out of bounds? For any indices that result in an empty slice? What should happen with negative indices? For slices where the start point >= end point and the stride isn't negative? Please be more specific as to why you want the error to be raised, because there are different scenarios that you may see as an error.
    • elegent
      elegent almost 9 years
      As I said "I want to raise an exception when both of the given slice indices are out of range". In all other cases the result would be the same as a "normal" size and return an empty list if a slice is not possible.
    • Martijn Pieters
      Martijn Pieters almost 9 years
      Then just test for both indices against the length of the list and raise an exception manually when both are out of range. You'll have to handle the None and negative cases, but that's it. There is no magic bullet here.
    • elegent
      elegent almost 9 years
      Thanks :) Ok that was exactly my question.