How to explain the reverse of a sequence by slice notation a[::-1]

I think the docs are perhaps a little misleading on this, but the optional arguments of slicing if omitted are the same as using None:

>>> a = "hello"
>>> a[::-1]
'olleh'
>>> a[None:None:-1]
'olleh'

You can see that these 2 above slices are identical from the CPython bytecode:

>>> import dis
>>> dis.dis('a[::-1]') # or dis.dis('a[None:None:-1]')
  1           0 LOAD_NAME                0 (a)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               0 (None)
              9 LOAD_CONST               2 (-1)
             12 BUILD_SLICE              3
             15 BINARY_SUBSCR
             16 RETURN_VALUE

For a negative step, the substituted values for None are len(a) - 1 for the start and -len(a) - 1 for the end:

>>> a[len(a)-1:-len(a)-1:-1]
'olleh'
>>> a[4:-6:-1]
'olleh'
>>> a[-1:-6:-1]
'olleh'

This may help you visualize it:

    h  e  l  l  o   
    0  1  2  3  4  5
-6 -5 -4 -3 -2 -1

a[0:5:-1] does not make much sense, since when you use this notation the indices mean: a[start:end:step]. When you use a negative step your end value needs to be at an "earlier" position than your start value.


All it does is slice. You pick. start stop and step so basically you're saying it should start at the beginning until the beginning but going backwards (-1).

If you do it with -2 it will skip letters:

>>> a[::-2]
'olh'

When doing [0:5:-1] your'e starting at the first letter and going back directly to 5 and thus it will stop. only if you try [-1::-1] will it correctly be able to go to the beginning by doing steps of negative 1.

Edit to answer comments

As pointed out the documentation says

an omitted second index defaults to the size of the string being sliced.

Lets assume we have str with len(str) = 5. When you slice the string and omit, leave out, the second number it defaults to the length of the string being sliced, in this case - 5. i.e str[1:] == str[1:5], str[2:] == str[2:5]. The sentence refers to the length of the original object and not the newly sliced object.

Also, this answer is great


You are confused with the behavior of the stepping. To get the same result, what you can do is:

a[0:5][::-1]
'olleh'

Indeed, stepping wants to 'circle' around backwards in your case, but you are limiting it's movement by calling a[0:5:-1].