Search code examples
pythonslicereverse

Python list error: [::-1] step on [:-1] slice


I thought I understood the basics of list slicing in python, but have been receiving an unexpected error while using a negative step on a slice, as follows:

>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-1:-1]
[]

(Note that this is being run in Python 3.5)

Why doesn't a[:-1:-1] reverse step through the a[:-1] slice in the same manner as it does through the whole list with a[::-1]?

I realize that you can use list.reverse() as well, but trying to understand the underlying python slice functionality better.


Solution

  • The first -1 in a[:-1:-1] doesn't mean what you think it does.

    In slicing, negative start/end indices are not interpreted literally. Instead, they are used to conveniently refer to the end of the list (i.e. they are relative to len(a)). This happens irrespectively of the direction of the slicing.

    This means that

    a[:-1:-1]
    

    is equivalent to

    a[:len(a)-1:-1]
    

    When omitted during reverse slicing, the start index defaults to len(a)-1, making the above equivalent to

    a[len(a)-1:len(a)-1:-1]
    

    This always gives an empty list, since the start and end indices are the same and the end index is exclusive.

    To slice in reverse up to, and including, the zeroth element you can use any of the following notations:

    >>> a[::-1]
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    >>> a[:None:-1]
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    >>> a[:-len(a)-1:-1]
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]