Without checking, I'm not sure whether a[-1:0:-1] reverses a list. I'm not sure if it includes the first element of the list or not [edit: It doesn't]. I'm not sure why in contrast a[::-1] does reverse a list. I found array slicing (and ranges) to be a source of confusion when programming the aforementioned linear algebra algorithms.
IMO, the Julia approach is better: 3:-1:1 produces [3,2,1]. Both the starting and ending points of the range are included.
That logic is pretty consistent. The start is always inclusive, so it needs to be `len(a)-`, `-`, or `None`. The end is always exclusive, so you need to choose `None`. As a result, counting all the syntactic sugar available to you, you have 8 slices that can reverse a list. To name a few you have a[::-1], a[None:None:-1], and a[-1::-1].
IMO a much more interesting example for the strengths of inclusive indexes is a[len(a)-1:-1:-1]. The result is always empty, but it wouldn't be too much of a stretch to think you included len(a)-1, you decremented to -1 exclusively (thus including 0), and hence reversed the entire list. The problem is that -1 is a valid index, and unlike the a[0:len(a)] case you don't have any values "before" the beginning of the list to include 0 in an _exclusive_ expression.
It's all a bit of a moot point though. I know Python especially chose its [inclusive,exclusive) convention largely because it wanted expressions like range(len(a)) to not require additional arithmetic for common use cases given that it had zero-based indexing. Julia has one-based indexing, so for common use cases an [inclusive,inclusive] pattern falls out as the most natural choice. I have no idea if Julia actually cared about that sort of thing or if such a convention came about by accident, but it seems like a clean choice for a one-based language.
The way Julia combines these in a mostly non-conflicting and non-confusing manner is a major engineering feat.
For example the following rule was found to be the just the right balance between permissive and strict behaviour:
* You are permitted to index into arrays with more indices than dimensions, but all trailing indices must be 1.
* You are permitted to index into arrays with fewer indices than dimensions, but the length of all the omitted dimensions must be 1.
Python should have used a different notation, imho. Like: a[<0] for the last element.
Looking for solutions, if you're stuck with Python and hate that behavior:
- If you don't need errors raised then a[~i] is already equal to a[-i-1].
- In your own code (or at its boundaries when wrapping external lists) it's nearly free and not much code to subclass list, override __getitem__, and raise errors for negative indices while responding to some syntax like a[0,] or a.R[0].