Inconsistent behaviour os str.find/str.index when providing optional parameters
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Thu Nov 22 03:44:21 EST 2012
On Wed, 21 Nov 2012 23:01:47 -0800, Giacomo Alzetta wrote:
> Il giorno giovedì 22 novembre 2012 05:00:39 UTC+1, MRAB ha scritto:
>> On 2012-11-22 03:41, Terry Reedy wrote: It can't return 5 because 5
>> isn't an index in 'spam'.
>>
>>
>>
>> It can't return 4 because 4 is below the start index.
>
> Uhm. Maybe you are right, because returning a greater value would cause
> an IndexError, but then, *why* is 4 returned???
>
>>>> 'spam'.find('', 4)
> 4
>>>> 'spam'[4]
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> IndexError: string index out of range
>
> 4 is not a valid index either. I do not think the behaviour was
> completely intentional.
The behaviour is certainly an edge case, but I think it is correct.
(Correct or not, it has been the same going all the way back to Python
1.5, before strings even had methods, so it almost certainly will not be
changed. Changing the behaviour now will very likely break hundreds,
maybe thousands, of Python programs that expect the current behaviour.)
Consider your string as a sequence of boxes, with index positions
labelled above the string:
0-1-2-3-4
|s|p|a|m|
The indexing model is that positions represent where you would cut
*between* characters, not the character itself. Slices are the substring
between cuts:
"spam"[1:3] => "pa"
while single indexes return the character to the right of the cut:
"spam"[1] => "p"
If there is no character to the right of the cut, indexing raises an
error.
Now, consider "spam".find(substring, start). This should return the
number of the first cut immediately to the left of the substring,
beginning the search at cut #start.
"spam".find("pa", 1) => 1
because cut #1 is immediately to the left of "pa" at index 1.
By this logic, "spam".find("", 4) should return 4, because cut #4 is
immediately to the left of the empty string. So Python's current
behaviour is justified.
What about "spam".find("", 5)? Well, if you look at the string with the
cuts marked as before:
0-1-2-3-4
|s|p|a|m|
you will see that there is no cut #5. Since there is no cut #5, we can't
sensibly say we found *anything* there, not even the empty string. If you
have four boxes, you can't say that you found anything in the fifth box.
I realise that this behaviour clashes somewhat with the slicing rule that
says that if the slice indexes go past the end of the string, you get an
empty string. But that rule is more for convenience than a fundamental
rule about strings.
I think there is legitimate room for disagreement about the "right"
behaviour here, but backwards compatibility trumps logical correctness
here, and it is very unlikely to be changed.
> The docstring does not describe this edge case, so I think it could be
> improved. If the first sentence(being an index in S) is kept, than it
> shouldn't say that start and end are treated as in slice notation,
> because that's actually not true.
+1
I think that you are right that the documentation needs to be improved.
--
Steven
More information about the Python-list
mailing list