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

From the python.org tutorial

Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced.

>>> a = "hello"
>>> print(a[::-1])
olleh

As the tutorial says a[::-1] should equals to a[0:5:-1]

but a[0:5:-1] is empty as follows:

>>> print(len(a[0:5:-1]))
0

The question is not a duplicate of explain-slice-notation. That question is about the general use of slicing in python.


Solution 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

Solution 2:

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].