Reputation: 563
I'm new to Python, and I find the slice behaviour somewhat confusing.
If I do
test = 'abcdefgh'
for i in range(7):
print test[-(8-i):-(6-i)]
print i
the last iteration will misbehave. Since slicing [start:end] doesn't include end, it seems to me like I'd need to handle slices like this with a special case if the last character is in the range I want.
Did I miss something?
Upvotes: 2
Views: 2784
Reputation: 114481
This is indeed an unfortunate consequence of the slice semantic.
The problem is that to mean "count from the end" you need to pass a negative number, and therefore you cannot ask "count 0 from the end" because -0 == 0
is not a negative number.
For counting 0 chars from the end you need to special case the issue with an if
or other conditional trickery, because passing 0
means "0 elements from the start".
To have it working for these cases the semantic would have to be that
-4
means counting 3 from the end (thus leaving room for -1 to mean "0 from the end"), but this would have been counter intuitive.
Being able to say x[-n:]
to mean the last n
chars of a string is a better compromise even if this doesn't work for n == 0
where instead of the empty string you get the full string.
Upvotes: 0
Reputation: 98
In the Python Tutorial (http://docs.python.org/2/tutorial/introduction.html), slice notation is defined as two indices separated by a colon.
In the last iteration of your example, the slice notation is [-2:0]. -2 is the index for the second to last character of the string, and 0 is the index for the first letter in the string. It does not make sense to take a slice from the second to last character to the first character.
If you want to go from the second to last character to the last character, simply eliminate the second index: [-2:]. That says, start at the second to last character and go to the end. Or be explicit and say [-2:len(test)].
For this example, I would suggest something like the following:
test = 'abcdefgh'
for i in range(7):
start = -(8-i)
end = -(6-i)
# test your end condition
if end == 0:
end = None
print test[start:end]
print i
Upvotes: 0
Reputation: 1153
The issue here is -0 just is 0, so you're attempting to grab up to the first character of the string
so for the case of i = 6 you get
test[-2:0] = ''
a better way of handling this is look ahead
for i in range(len(test)-1):
print test[i:i+2]
for indexing from the end to work the correct syntax would leave out the 0
test[-2:] = 'gh'
Upvotes: 1
Reputation: 1725
You can't start at -1 and go to +1. -1 is the end, 1 the secund item. You can do
for i in range(7):
....: print test[i:(2+i)]
....:
ab
bc
cd
de
ef
fg
gh
Upvotes: 1
Reputation: 23221
If you add another couple prints, you can see what's happening:
test = 'abcdefgh'
for i in range(7):
print -(8-i), -(6-i)
print test[-(8-i):-(6-i)]
print i
Outputs:
-8 -6
ab
0
-7 -5
bc
1
-6 -4
cd
2
-5 -3
de
3
-4 -2
ef
4
-3 -1
fg
5
-2 0
All your ranges are negative, until the last, when it's 0
Adding or None
to the end range will to avoid the 0
and act as if you didn't pass it in the first place:
for i in range(7):
print test[-(8-i):(-(6-i) or None)]
print i
Which outputs:
ab
0
bc
1
cd
2
de
3
ef
4
fg
5
gh
6
The way the or
operator works, if the first argument is "falsish", the second argument is used, in this case None
Upvotes: 1