Get the Index of an Element in a Python List (index, all matches)

To get the index of an element in a Python list, call .index() on the list:

fruits = ["apple", "pear", "plum"]
fruits.index("pear")        # 1

Two things to know before you rely on it. It returns only the first match, and a value that is not there raises ValueError rather than returning -1.

Both have straightforward fixes, covered below along with finding every occurrence and what to do with NumPy arrays. Output is from Python 3.12.5.

Diagram of a Python list showing that the index method returns only the first matching position
.index() stops at the first match and never mentions the second.

Using list.index() to find an element

The method takes the value you are looking for and gives back its position:

fruits = ["apple", "pear", "plum", "pear"]

print("fruits.index('pear')  ->", fruits.index("pear"))
print("fruits.index('plum')  ->", fruits.index("plum"))
print()
print("positions count from 0, so 'apple' is 0 and 'pear' is 1.")
print("Note that 'pear' appears twice and only the FIRST is reported.")

Output:

fruits.index('pear')  -> 1
fruits.index('plum')  -> 2

positions count from 0, so 'apple' is 0 and 'pear' is 1.
Note that 'pear' appears twice and only the FIRST is reported.
Command Prompt showing the Python list index method returning the position of an element
.index() returns the position of the first match.

Positions start at 0, so the first item is at index 0. That is the same numbering used by slicing and by range(len(items)).

Why index() raises ValueError instead of returning -1

A missing value is treated as a mistake, not as a result:

fruits = ["apple", "pear", "plum"]

try:
    fruits.index("kiwi")
except ValueError as err:
    print("fruits.index('kiwi') -> ValueError:", err)

print()
print("an empty list behaves the same way:")
try:
    [].index(1)
except ValueError as err:
    print("[].index(1) -> ValueError:", err)

print()
print("so a missing value is an exception, not a -1 or a None.")

Output:

fruits.index('kiwi') -> ValueError: 'kiwi' is not in list

an empty list behaves the same way:
[].index(1) -> ValueError: 1 is not in list

so a missing value is an exception, not a -1 or a None.
Command Prompt showing the Python ValueError raised when a value is not in the list
A missing value raises ValueError: 'kiwi' is not in list.

This is deliberate. Returning -1 would be a valid index in Python, since negative indexes count from the end, so items[-1] would silently hand back the last item instead of signalling a miss.

Python has no indexOf method

If you arrived from JavaScript, the method you want is spelled differently and behaves differently:

print("Python lists do not have the methods you may be looking for:")
print("  hasattr(list, 'indexOf') ->", hasattr(list, "indexOf"))
print("  hasattr(list, 'find')    ->", hasattr(list, "find"))
print("  hasattr(list, 'index')   ->", hasattr(list, "index"))
print()

print("STRINGS do have find, and it returns -1 instead of raising:")
print("  'hello'.find('z')  ->", "hello".find("z"))
print("  'hello'.find('ll') ->", "hello".find("ll"))
print()
print("  'hello'.index('z') ->", end=" ")
try:
    "hello".index("z")
except ValueError as err:
    print("ValueError:", err)
print()
print("So: lists get .index() only. Strings get both .find() and .index().")

Output:

Python lists do not have the methods you may be looking for:
  hasattr(list, 'indexOf') -> False
  hasattr(list, 'find')    -> False
  hasattr(list, 'index')   -> True

STRINGS do have find, and it returns -1 instead of raising:
  'hello'.find('z')  -> -1
  'hello'.find('ll') -> 2

  'hello'.index('z') -> ValueError: substring not found

So: lists get .index() only. Strings get both .find() and .index().
Command Prompt showing that Python lists have no indexOf or find method while strings have find
Lists have .index() only; strings also have .find().
You wantJavaScriptPython
Position, or a miss signalarr.indexOf(x) returns -1list.index(x) raises ValueError
Position in a stringstr.indexOf(x) returns -1str.find(x) returns -1
Is it there at all?arr.includes(x)x in list
Every positionloop or flatMap[i for i, v in enumerate(list) if v == x]

str.find() is the closest match to indexOf and it does return -1. Lists simply never got an equivalent.

Getting the index without an exception

Three ways to turn a miss into a value you can test:

fruits = ["apple", "pear", "plum"]

def index_or(items, value, default=-1):
    """The equivalent of JavaScript's indexOf."""
    return next((i for i, item in enumerate(items) if item == value), default)

print("index_or(fruits, 'pear') ->", index_or(fruits, "pear"))
print("index_or(fruits, 'kiwi') ->", index_or(fruits, "kiwi"), " no exception")
print("index_or(fruits, 'kiwi', None) ->", index_or(fruits, "kiwi", None))
print()

print("or handle the exception where it happens:")
try:
    position = fruits.index("kiwi")
except ValueError:
    position = -1
print("  position ->", position)
print()

print("checking first also works, but scans the list twice:")
position = fruits.index("pear") if "pear" in fruits else -1
print("  position ->", position)

Output:

index_or(fruits, 'pear') -> 1
index_or(fruits, 'kiwi') -> -1  no exception
index_or(fruits, 'kiwi', None) -> None

or handle the exception where it happens:
  position -> -1

checking first also works, but scans the list twice:
  position -> 1

The next(...) form is the closest thing to indexOf, and the default is yours to choose. Use None rather than -1 if there is any chance the result gets used as an index later.

Wrapping the call in try is equally valid and reads well when a miss is genuinely unexpected. Checking with in first works too, but walks the list twice. Checking whether a list contains a value covers that test on its own.

Find all indexes of an element in a list

.index() stops at the first match, so repeats need a comprehension:

fruits = ["apple", "pear", "plum", "pear", "pear"]

print("the list          ->", fruits)
print("fruits.index('pear') ->", fruits.index("pear"), " first only")
print()

positions = [i for i, fruit in enumerate(fruits) if fruit == "pear"]
print("every position    ->", positions)
print("how many          ->", len(positions))
print("last one          ->", positions[-1])
print()

print("the same idea with a condition instead of a value:")
numbers = [4, 9, 2, 9, 1]
print("  numbers          ->", numbers)
print("  positions over 3 ->", [i for i, n in enumerate(numbers) if n > 3])

Output:

the list          -> ['apple', 'pear', 'plum', 'pear', 'pear']
fruits.index('pear') -> 1  first only

every position    -> [1, 3, 4]
how many          -> 3
last one          -> 4

the same idea with a condition instead of a value:
  numbers          -> [4, 9, 2, 9, 1]
  positions over 3 -> [0, 1, 3]
Command Prompt showing how to find all indexes of a repeated element in a Python list using enumerate
A comprehension over enumerate() returns every matching position.

The same pattern takes a condition instead of a value, which is how you find every position above a threshold or every string starting with a letter.

It returns an empty list when nothing matches, so there is no exception to handle. Looping with an index explains the enumerate() part.

Searching from a given position

.index() accepts start and end arguments:

fruits = ["apple", "pear", "plum", "pear"]

print("searching from a position onwards:")
print("  fruits.index('pear')    ->", fruits.index("pear"))
print("  fruits.index('pear', 2) ->", fruits.index("pear", 2), " skips the first one")
print()

print("with an end position too, which is exclusive:")
print("  fruits.index('pear', 0, 2) ->", fruits.index("pear", 0, 2))
try:
    fruits.index("pear", 2, 3)
except ValueError as err:
    print("  fruits.index('pear', 2, 3) ->  ValueError:", err)
print()
print("this is how you walk through repeats one at a time,")
print("though the comprehension above is usually clearer.")

Output:

searching from a position onwards:
  fruits.index('pear')    -> 1
  fruits.index('pear', 2) -> 3  skips the first one

with an end position too, which is exclusive:
  fruits.index('pear', 0, 2) -> 1
  fruits.index('pear', 2, 3) ->  ValueError: 'pear' is not in list

this is how you walk through repeats one at a time,
though the comprehension above is usually clearer.

The end position is exclusive, matching slicing. Calling it repeatedly with a moving start is the classic way to step through repeats, though the comprehension above is easier to read.

index() compares with equality, not identity

This produces results that look wrong until you see why:

mixed = [1.0, 1, True]

print("the list ->", mixed)
print("mixed.index(1) ->", mixed.index(1))
print()
print("1.0 == 1 is", 1.0 == 1, "so the float matched first.")
print(".index() compares with == , not with 'is the same object'.")
print()

print("True is even stranger:")
print("  True == 1   ->", True == 1)
print("  [True].index(1) ->", [True].index(1))
print()

print("case matters for strings:")
names = ["Ann", "bob"]
try:
    nam