Is there any significant difference in term of speed other than potential overheads if we have to enclose
s.index()within atry/except.
In (C)Python at least, find, index, rfind, rindex are all wrappers around an internal function any_find_slice.
The implementation is the same. The only difference is that index and rindex will raise a ValueError for you if it finds that the result of calling any_find_slice is -1.
If you went ahead and timed these you'd see how there's clearly no meaningful difference between them:
➜ ~ python -m perf timeit -s "s = 'a' * 1000 + 'b'" "s.find('b')"
Median +- std dev: 399 ns +- 7 ns
➜ ~ python -m perf timeit -s "s = 'a' * 1000 + 'b'" "s.index('b')"
Median +- std dev: 396 ns +- 3 ns
I'm using perf for the timings here.
I'm guessing in other implementations of Python this shouldn't differ. Both methods do the same thing and differ only in how they react when the requested element was not found.
Answer from Dimitris Fasarakis Hilliard on Stack OverflowIs there any significant difference in term of speed other than potential overheads if we have to enclose
s.index()within atry/except.
In (C)Python at least, find, index, rfind, rindex are all wrappers around an internal function any_find_slice.
The implementation is the same. The only difference is that index and rindex will raise a ValueError for you if it finds that the result of calling any_find_slice is -1.
If you went ahead and timed these you'd see how there's clearly no meaningful difference between them:
➜ ~ python -m perf timeit -s "s = 'a' * 1000 + 'b'" "s.find('b')"
Median +- std dev: 399 ns +- 7 ns
➜ ~ python -m perf timeit -s "s = 'a' * 1000 + 'b'" "s.index('b')"
Median +- std dev: 396 ns +- 3 ns
I'm using perf for the timings here.
I'm guessing in other implementations of Python this shouldn't differ. Both methods do the same thing and differ only in how they react when the requested element was not found.
@Dimitris's answer showed that s.find() and s.index() perform equally well if the substring is found.
But as @augustomen pointed out, if the substring is not found then s.index() will be significantly slower due to the exception handling. We can test this with the following code snippets.
Note that I'm using a different machine to @Dimitris so my timings cannot be compared with his.
$ python3 -m timeit -s "s = 'a' * 1000" "s.find('b')"
5000000 loops, best of 5: 87.3 nsec per loop
$ python3 -m timeit -s "s = 'a' * 1000" "try: s.index('b')" "except ValueError: pass"
1000000 loops, best of 5: 242 nsec per loop
It's clear that s.find() is the winner when the substring is not found, but is that just because we didn't include a try/except block for it?
Let's try adding a try/except block to s.find() (even though we know it won't be triggered).
$ python3 -m timeit -s "s = 'a' * 1000" "try: s.find('b')" "except ValueError: pass"
5000000 loops, best of 5: 89.1 nsec per loop
We see here that the mere presence of a try/except block barely alters the time at all. It's only when the exception is actually triggered that we incur a meaningful hit to performance.
The moral of the story is to use s.find() if there's a reasonable chance that the substring won't be found.
If you're sure that the substring will almost always be found then you can use either s.find() or s.index(). You might prefer s.index() in that case, because the try/except syntax signals to other developers that you are handling an edge case that you don't expect will occur very often.
I think you're expecting rfind to return the index of the rightmost character in the first/leftmost match for "what". It actually returns the index of the leftmost character in the last/rightmost match for "what". To quote the documentation:
str.rfind(sub[, start[, end]])Return the highest index in the string where substring sub is found, such that sub is contained within
s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return-1on failure.
"ab c ab".find("ab") would be 0, because the leftmost occurrence is on the left end.
"ab c ab".rfind("ab") would be 5, because the rightmost occurrence is starts at that index.
find() will return the index of the first match. But rfind will give you the last occurence of the pattern. It will be clear if you try to match repeated match case.
check this Example >>> string='hey! how are you harish'
>>>string.find('h')
>>>0 #it matched for first 'h' in the string
>>> string.rfind('h')
22 #it matched for the last 'h' in the string
str.find returns -1 when it does not find the substring.
>>> line = 'hi, this is ABC oh my god!!'
>>> line.find('?')
-1
While str.index raises ValueError:
>>> line.index('?')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
Both the functions behave the same way if a sub-string is found.
Also find is only available for strings where as index is available for lists, tuples and strings
>>> somelist
['Ok', "let's", 'try', 'this', 'out']
>>> type(somelist)
<class 'list'>
>>> somelist.index("try")
2
>>> somelist.find("try")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'find'
>>> sometuple
('Ok', "let's", 'try', 'this', 'out')
>>> type(sometuple)
<class 'tuple'>
>>> sometuple.index("try")
2
>>> sometuple.find("try")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'find'
>>> somelist2
"Ok let's try this"
>>> type(somelist2)
<class 'str'>
>>> somelist2.index("try")
9
>>> somelist2.find("try")
9
>>> somelist2.find("t")
5
>>> somelist2.index("t")
5