str.find()

Locate a substring: its first index, or -1 when absent — the non-raising sibling of str.index.

String methodPython 2.0+Live demo
Common call
"hello".find("l")
Returns
int index, or -1 when absent
Replaces
str.index raises ValueError instead of returning -1
Watch out
-1 is truthy — "if s.find(x):" is a classic bug
str.find(subsub — The substring to locate.type: str · required, startstart — Slice start, supports negative indexing.type: int · default: 0=0, endend — Slice end (exclusive), supports negative indexing.type: int · default: len(s)=len(s))
→ int

Demo

Live evaluation
Try:
Inputs
stringstrthe source
substrto locate
startintsearch from
Output
'hello world'.find('o')
4

find scans left to right and reports the FIRST match. A missing substring returns -1 — no exception. The optional start restricts where the search begins.

Parameters

NameTypeRequiredDescription
substryesThe substring to locate.
startintno (0)Slice start, supports negative indexing.
endintno (len(s))Slice end (exclusive), supports negative indexing.

Return value

int — The lowest index where sub is found, or -1 when it does not occur. Never raises for a missing substring.

Common patterns

Check-then-slice
Find a marker and slice relative to it.
i = s.find(":")
if i != -1:
    value = s[i + 1:]
Existence check — prefer "in"
When you only need yes/no, the in operator says it better.
if "@" in email:   # not: email.find("@") != -1
    ...
Search from the right
rfind reports the LAST occurrence.
ext = path[path.rfind(".") + 1:]

Examples

1. First occurrence
"hello".find("l")
Returns
2
2. Missing substring
"hello".find("z")
Returns
-1
3. Search from an index
"hello world".find("o", 5)
Returns
7
4. Empty sub matches at 0
"abc".find("")
Returns
0

Pitfalls

1. -1 is truthy
Testing find() directly as a boolean inverts the logic: 0 (found at start) is falsy, -1 (absent) is truthy.
Backwards
if "hello".find("h"):
    print("found")
nothing — index 0 is falsy
Fix
if "hello".find("h") != -1:
    print("found")
found
2. find vs index
Same search, different failure mode — pick by whether absence is an error.
Silent -1 travels
pos = s.find(marker)
value = s[pos:]  # pos may be -1!
slice from -1 = last char — silently wrong
Fail fast
pos = s.index(marker)  # raises if absent
value = s[pos:]
ValueError at the real problem site

When to use

Use it
  • You need the position, and absence is a normal case
  • Slicing around a found marker
Reach for something else
  • Existence only → "sub" in s
  • Absence is a bug → str.index (raises)
  • Last occurrence → str.rfind
  • Pattern matching → re.search

Notes

Complexity
O(n·m) worst case; tuned two-way search in practice
Return
int (or -1)
CPython impl
Objects/unicodeobject.c :: unicode_find
Memory
No allocation
Thread-safe
Yes — str is immutable

FAQ

Identical search; find returns -1 for a missing substring while index raises ValueError. Use index when absence means a bug.

History

2.0
Method available on the unified string type.