It starts counting from "2" going backwards (step -1) until "-5" is reached - but reaching the element "-5" would require positive step in this case.
For example the output of:
i[2::-1]
is:
[2, 1, 0]
It starts counting from "2" going backwards (step -1) until "-5" is reached - but reaching the element "-5" would require positive step in this case.
For example the output of:
i[2::-1]
is:
[2, 1, 0]
As it turns out, when going from left to right (using negative or positive version of index), a positive step size is required.
Going from right to left requires a negative step size:
i = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1]
# to get 6, 7, 8
print(i[6:9])
print(i[-4:-1:1])
print(i[6:-1:1])
print(i[-4:9:1])
# to get 8, 7, 6
print(i[8:5:-1])
print(i[-2:-5:-1])
print(i[-2:5:-1])
print(i[8:-5:-1])
I was pointed to the reference implementation (hattip to the Anonymous Benefactor) and found that it is fairly straightforward to understand the behavior from there. To be complete, IMHO this behavior is unintuitive, but it nevertheless is well defined and matches the reference implementation.
Two CPython files are relevant, namely the ones describing list_subscript and PySlice_AdjustIndices. When retrieving a slice from a list as in this case, list_subscript is called. It calls PySlice_GetIndicesEx, which in turn calls PySlice_AdjustIndices. Now PySlice_AdjustIndices contains simple if/then statements, which adjust the indices. In the end it returns the length of the slice. To our case, the lines
if (*stop < 0) {
*stop += length;
if (*stop < 0) {
*stop = (step < 0) ? -1 : 0;
}
}
are of particular relevance. After the adjustment, x[0:-len(x)-1:-1] becomes x[0:-1:-1] and the length 1 is returned. However, when x[0:-1:-1] is passed to adjust, it becomes x[0:len(x)-1:-1] of length 0. In other words, f(x) != f(f(x)) in this case.
It is amusing to note that there is the following comment in PySlice_AdjustIndices:
/* this is harder to get right than you might think */
Finally, note that the handing of the situation in question is not described in the python docs.
The fact that
> x[-1:-4:-1]
[6, 5, 4]
> x[0:-4:-1]
[]
should not surprise you! It is fairly obvious that you can slice a list from the last to the fourth-last element in backwards steps, but not from the first element.
In
x[0:i:-1]
the i must be < -len(x) in order to resolve to an index < 0 for the result to contain an element.
The syntax of slice is simple that way:
x[start:end:step]
means, the slice starts at start (here: 0) and ends before end (or the index referenced by any negative end). -len(x) resolves to 0, ergo a slice starting at 0 and ending at 0 is of length 0, contains no elements. -len(x)-1, however, will resolve to the actual -1, resulting in a slice of length 1 starting at 0.
Leaving end empty in a backward slice is more intuitively understood:
> l[2::-1]
[3, 2, 1]
> l[0::-1]
[1]
Negative Slicing in Python
Negative step indexing on List in Python - Stack Overflow
Why does Python refuse to slice a list with negative step?
List slicing with negative index
Although I know how slicing works but following examples kind of stumped me.
values = [3,4,3,7,8,9,5] values[:3:-1] #o/p [5,9,8] values[5:3:-1] #o/p [9,8]
I always thought in list[start:stop:step], 'start' defaults to 0, 'stop' defaults to length-1 and 'step' defaults to 1. But this doesn't make sense here. What are the rules? Link to official docs will also be appreciated as I couldn't find that.
[-1:0:-1] means: start from the index len(string)-1 and move up to 0(not included) and take a step of -1(reverse).
So, the following indexes are fetched:
le-1, le-1-1, le-1-1-1 .... 1 # le is len(string)
example:
In [24]: strs = 'foobar'
In [25]: le = len(strs)
In [26]: strs[-1:0:-1] # the first -1 is equivalent to len(strs)-1
Out[26]: 'raboo'
In [27]: strs[le-1:0:-1]
Out[27]: 'raboo'
The Python documentation (here's the technical one; the explanation for range() is a bit easier to understand) is more correct than the simplified "every kth element" explanation. The slicing parameters are aptly named
slice[start:stop:step]
so the slice starts at the location defined by start, stops before the location stop is reached, and moves from one position to the next by step items.