We basic of python slice notation can be summarized in just few lines as mentioned below..
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
a[start:stop:step] # start through not past stop, by step
The key point to remember is that the :stop value represents the first value that is not in the selected slice. So, the difference between stop and start is the number of elements selected (if step is 1, the default).
Next important point is abnout the negative numbers i.e what if the start or stop may be a negative number, which means it counts from the end of the array instead of the beginning. So:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Similarly, step may be a negative number:
a[::-1] # all items in the array, reversed
a[1::-1] # the first two items, reversed
a[:-3:-1] # the last two items, reversed
a[-3::-1] # everything except the last two items, reversed
No errors are thrown if it is numbers put are not in the range.. i.e.
a[:-5] # just return an empty() array instead of an error
a[10::-1] # return [3,2,1]
It will give you the best possible outcome or empty if not possible but if you expect error then be aware of this situation
Relation to slice() object
The slicing operator  is actually being used in the above code with a slice() object using the : notation (which is only valid within ), i.e.:
a[start:stop:step] is equivalent to: a[slice(start, stop, step)]
Slice objects also behave slightly differently depending on the number of arguments, similarly to range(), i.e. both slice(stop) and slice(start, stop[, step]) are supported. To skip specifying a given argument, one might use None, so that e.g. a[start:] is equivalent to a[slice(start, None)] or a[::-1] is equivalent to a[slice(None, None, -1)].