This post originated from an RSS feed registered with Python Buzz
by Thomas Guest.
Original Post: Negative Sequence Indices in Python
Feed Title: Word Aligned: Category Python
Feed URL: http://feeds.feedburner.com/WordAlignedCategoryPython
Feed Description: Dynamic languages in general. Python in particular. The adventures of a space sensitive programmer.
Supply a negative index when accessing a sequence and Python counts back from the end. So, for example, my_list[-2] is the penultimate element of my_list, which is much better than my_list[len(my_list)-2] or even *(++my_list.rbegin()).
That final example uses one of C++’s reverse iterators. It gets the penultimate element of a collection by advancing an iterator from the reversed beginning of that collection. If you’re addicted to negative indices you can use them with C++ arrays, sort of.
Compiling and running this program outputs the string “org”.
Going back to Python, the valid indices into a sequence of length L are -L, -L+1, … , 0, 1, … L-1. Whenever you write code to calculate an index used for accessing a sequence, and especially if you’re catching any resulting IndexErrors, it’s worth checking if the result of the calculation can be negative, and if — in this case — you really do want the from-the-back indexing behaviour.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
…
W
O
R
D
A
L
I
G
N
E
D
…
-14
-13
-12
-11
-10
-9
-8
-7
-6
-5
-4
-3
-2
-1
The power of negative indices increases with slicing. Take a slice of a sequence by supplying begin and end indices.
I prefer the list(digits) form for copying digits but you should certainly be familiar with the digits[:] version.
You can supply any indices as slice limits, even ones which wouldn’t be valid for item access. Imagine laying your sequence out on an indexed chopping board, slicing it at the specified points, then taking whatever lies between these points.
>>> digits[-1000000]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> digits[1000000]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> digits[-1000000:1000000]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
This parameter too can be negative. The sign of the step affects which limiting values the begin and end slice parameters default to. It’s subtle behaviour, but you soon get used to it.
How do you reverse a string? Slice it back to front!
>>> domain[::-1]
'gro.dengiladrow'
To recap: the default slice limits are the start and end of the sequence, 0 and -1, or -1 and 0 if the step is negative. The default step is 1 whichever way round the limits are. When slicing, s[i:j:k], i and j may take any integer value, and k can take any integer value except0.
The zero value creates another interesting edge case. Here’s a function to return the last n items of a sequence.