[Tutor] Counting a string backwards

Steven D'Aprano steve at pearwood.info
Sun May 28 22:00:26 EDT 2017


On Sun, May 28, 2017 at 01:58:22PM -0400, C W wrote:
> Dear Python list,
> 
> I am having trouble understanding the following.
[...]


The way to think about string indexing and slicing is that the index 
positions mark *between* the characters. Take your string:

    Machine learning is awesome!

For brevity, I'll just use the first word:

    Machine

Imagine slicing it between the characters. I'll mark the cuts with a 
vertical bar:

    |M|a|c|h|i|n|e|

and add indexes. The indexes will only line correctly if you use a 
monspaced or fixed width font like Courier, otherwise things may not 
line up correctly.

    |M|a|c|h|i|n|e|
    0 1 2 3 4 5 6 7

Here they are again starting from the right, I've spread things out a 
bit to fit in the minus signs:

   |M  |a  |c  |h  |i  |n  |e  |
   -7  -6  -5  -4  -3  -2  -1  0

Notice that 0 gets used twice. Of course, that's impossible, because it 
would be ambiguous. If you give 0 as an index, how does Python know 
whether you mean 0 at the start or 0 or the end? So the simple rule 
Python uses is that 0 *always* means the start.

When you give a single index, Python always uses the character 
immediately to the right of the cut:

s = "Machine"
s[0] 
=> returns "M"

s[-1]
=> returns "e"

s[7]
=> raises an exception, because there is no character to the right

When you give two indexes, using slice notation, Python returns the 
characters BETWEEN those cuts:

s[0:7]
=> returns "Machine"

s[1:-1]
=> returns "achin"

Because 0 always means the start of the string, how do you slice to the 
end? You can use the length of the string (in this case, 7) or you can 
leave the ending position blank, and it defaults to the length of the 
string:

s[1:]  # means the same as [1:len(s)]

You can leave the starting position blank too, it defaults to 0:

s[:]  # means the same as [0:len(s)]

So remember that slices always cut *between* the index positions.


Things get complicated when you include a step (or stride), especially 
when the step is negative. For step sizes other than 1, it is 
probably best to think of looping over the string:

py> s = "Nobody expects the Spanish Inquisition!"
py> s[-1:1:-2]
'!otsun snp h tex db'

is somewhat like:

for i in range(len(s)-1, 1, -2):
    print s[i]



-- 
Steve


More information about the Tutor mailing list