101

I am new to python and cannot quite understand the difference between find and index.

>>> line
'hi, this is ABC oh my god!!'
>>> line.find("o")
16
>>> line.index("o")
16

They always return the same result. Thanks!!

falsetru
  • 357,413
  • 63
  • 732
  • 636
SohamC
  • 2,367
  • 6
  • 22
  • 34

3 Answers3

134

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.

Mohammed H
  • 6,880
  • 16
  • 81
  • 127
falsetru
  • 357,413
  • 63
  • 732
  • 636
  • 1
    and if a substring is found, both the functions behave the same way? – SohamC Mar 05 '14 at 06:54
  • @user1603970, Yes, they do. Their parameters are also same. – falsetru Mar 05 '14 at 07:01
  • @user1603970, According to the `index` documentation I linked in the answer: Like find(), but raise ValueError when the substring is not found. – falsetru Mar 05 '14 at 07:03
  • as @reep mentioned, find is only available for strings where as index is available for lists, tuples and strings – raja777m Mar 31 '20 at 12:09
  • 2
    python should drop one of these two methods. One of them serve the purpose well. Also i think it's more appropriate for `index` to return `-1` and `find ` return `ValueError` in case `sub` is not found. – pouya Apr 26 '20 at 17:04
  • I know its an old comment but since someone upvoted it I have to point out that wanting `list.index` to return `-1` is wrong, as `-1` indicates the last element, negative indexing, the method name index returns an index @pouya – python_user Nov 28 '20 at 09:49
  • 1
    @python_learner We know both `find` and `index` returns the lowest **positive** index in the string where substring `sub` is found. So a negative index is irrelevant here. Also your logic can be applied to the `find` method as well. Anyway it's better for python to drop `index` in favor of `find` which is better and saner to return `ValueError` in case `sub` is not found. – pouya Nov 28 '20 at 10:19
  • I stand by what I said, index is supposed to return an index and in case it did return `-1` it would point to the last element so `ValueError` makes more sense, where as `find` returning `-1` when not found is more to its nature of "finding", the names themselves are clear imo – python_user Nov 28 '20 at 13:22
  • 1
    ``index`` is a [sequence method](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) with well-defined behaviour, including to raise ``ValueError`` if no match is found: "``index`` raises ``ValueError`` when ``x`` is not found in ``s``." What the specific ``str.find`` method does is entirely inconsequential for the larger picture that ``str.index`` has to be consistent with. – MisterMiyagi Nov 28 '20 at 13:22
30

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
Reep
  • 546
  • 6
  • 11
10

@falsetru provided an explanation about the difference between functions, I did a performance test between them.

"""Performance tests of 'find' and 'index' functions.

Results:
using_index t = 0.0259 sec
using_index t = 0.0290 sec
using_index t = 0.6851 sec

using_find t = 0.0301 sec
using_find t = 0.0282 sec
using_find t = 0.6875 sec

Summary:
    Both (find and index) functions have the same performance.
"""


def using_index(text: str, find: str) -> str:
    """Returns index position if found otherwise raises ValueError."""
    return text.index(find)


def using_find(text: str, find: str) -> str:
    """Returns index position if found otherwise -1."""
    return text.find(find)


if __name__ == "__main__":
    from timeit import timeit

    texts = [
        "short text to search" * 10,
        "long text to search" * 10000,
        "long_text_with_find_at_the_end" * 10000 + " to long",
    ]

    for f in [using_index, using_find]:
        for text in texts:
            t = timeit(stmt="f(text, ' ')", number=10000, globals=globals())
            print(f"{f.__name__} {t = :.4f} sec")
        print()
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
  • So the more specific `str.find` is not better optimized than `seq.index`. Why not combine both by introducing an argument so that, say, `str.index(sub, panic=False) == str.find(sub)`? :) – SnzFor16Min Aug 14 '23 at 09:25