The list.index() method returns the zero-based index of the first matching item in a list.
Positional Lookup & Bounded Ranges: You can constrain searches to a sub-slice using optional start and end parameters. If the item is missing, Python raises a ValueError instead of returning -1. To count total matches, see list.count(). To remove elements by index or value, see list.pop() and list.remove().
The index() method takes one mandatory argument and two optional range bounds:
# Formal syntax of list.index()
list_instance.index(value[, start[, end]])
| Parameter | Type | Default | Description & Operational Rule |
|---|---|---|---|
value |
Any |
Required | The target item to search for. Tested using equality (item == value). |
start |
int |
0 |
Optional starting index position (inclusive). |
end |
int |
len(list) |
Optional ending boundary (exclusive; stops before this index). |
| Return | int |
N/A | Zero-based integer index of the first matching element. |
| Time Complexity | O(N) | N/A | Linear search from start to end index. |
Calling index() returns the zero-based index corresponding to the target element:
# 1. Basic search: finding the zero-based index of an element
items = ['apple', 'banana', 'cherry', 'date']
pos_banana = items.index('banana')
pos_date = items.index('date')
print("Index of 'banana':", pos_banana)
print("Index of 'date': ", pos_date)Terminal Output:
Index of 'banana': 1
Index of 'date': 3
When multiple elements match the search value, index() halts immediately at the first match:
# 2. Duplicate elements: index() returns only the first match
scores = [10, 50, 25, 50, 90, 50]
first_pos = scores.index(50)
print("First match of 50 is at index:", first_pos)Terminal Output:
First match of 50 is at index: 1
Supplying start and end parameters restricts the search to a half-open window [start, end):
# 3. Constraining searches with start and end index bounds
letters = ['a', 'b', 'c', 'b', 'a', 'd', 'b']
# Start search at index 2 (skips 'b' at index 1)
pos_second_b = letters.index('b', 2)
print("Second 'b' found at index:", pos_second_b)
# Bound search between indices 2 and 5 (half-open [2, 5))
pos_bounded = letters.index('a', 2, 5)
print("'a' between [2, 5) index:", pos_bounded)Terminal Output:
Second 'b' found at index: 3
'a' between [2, 5) index: 4
Negative integers count backward from the list tail, but the returned index is always normalized from 0:
# 4. Using negative start and end indices
colors = ['red', 'green', 'blue', 'green', 'yellow']
# Search starting from 2nd item from the end (-2 -> index 3)
pos_neg = colors.index('green', -2)
print("Index found using negative start:", pos_neg)Terminal Output:
Index found using negative start: 3
Unlike string find() which returns -1 on failure, list.index() raises a ValueError:
# 5. Handling ValueError: membership check vs. try-except
team = ['Alex', 'Ronald', 'John']
target = 'Ravi'
# Approach A: Pre-check membership with 'in'
if target in team:
print("Found at:", team.index(target))
else:
print(f"Pre-check: '{target}' not present in list.")
# Approach B: Intercept ValueError with try-except
try:
print(team.index(target))
except ValueError as err:
print("Exception caught: ", err)Terminal Output:
Pre-check: 'Ravi' not present in list.
Exception caught: 'Ravi' is not in list
To collect every index where a duplicate value appears, use list comprehension with enumerate():
# 6. Finding all matching indices: Comprehension vs. While Loop
raw_data = ['a', 'b', 'c', 'b', 'a', 'b']
# Idiomatic Approach: List comprehension with enumerate()
all_b_indices = [idx for idx, val in enumerate(raw_data) if val == 'b']
print("All indices of 'b':", all_b_indices)Terminal Output:
All indices of 'b': [1, 3, 5]
Building an iterative index scanner generator using progressive start offsets:
# 7. Production Recipe: Multi-Occurrence Index Scanner Generator
def scan_all_indices(sequence: list, target_val):
"""Yields all matching indices using list.index() in step jumps."""
start = 0
while True:
try:
found_idx = sequence.index(target_val, start)
yield found_idx
start = found_idx + 1
except ValueError:
break
logs = ["INFO", "WARN", "ERROR", "INFO", "ERROR", "DEBUG"]
error_positions = list(scan_all_indices(logs, "ERROR"))
print("Positions of 'ERROR' logs:", error_positions)Terminal Output:
Positions of 'ERROR' logs: [2, 4]Reordering items dynamically by locating position and popping to top priority:
# 8. Production Recipe: Reordering Items by Priority
def promote_to_top(task_list: list, task_name: str) -> bool:
"""Finds a task by name and moves it to the top of the queue."""
try:
idx = task_list.index(task_name)
task_list.insert(0, task_list.pop(idx))
return True
except ValueError:
return False
tasks = ["Cleanup", "Build", "Deploy", "Test"]
promote_to_top(tasks, "Deploy")
print("Queue after promoting 'Deploy':", tasks)Terminal Output:
Queue after promoting 'Deploy': ['Deploy', 'Cleanup', 'Build', 'Test']
Beware of the exclusive end boundary and boolean-integer type equality:
# 9. Common traps: Half-open interval and True == 1 equality
numbers = [10, 20, 30, 40]
# Trap 1: End index is exclusive! Index 2 (value 30) is not inspected:
try:
numbers.index(30, 0, 2)
except ValueError as err:
print("Exclusive bound trap:", err)
# Trap 2: True == 1 equality match
mixed = [True, 1, 2]
print("Index of integer 1: ", mixed.index(1)) # Returns 0 because True == 1!Terminal Output:
Exclusive bound trap: 30 is not in list
Index of integer 1: 0
Practice positional searches, bounded intervals, and multi-occurrence scanning in our interactive companion Jupyter Notebook:
Explore interactive code cells, benchmark search ranges, test ValueError handling, and run self-validating assertions.
View on GitHub Run in Google ColabRun these unit checks directly in Python or your local environment to verify index() mechanics:
# 10. Self-verifying unit test suite for list.index()
# Test 1: Basic zero-based index lookup
data = ["alpha", "beta", "gamma"]
assert data.index("alpha") == 0
assert data.index("beta") == 1
assert data.index("gamma") == 2
# Test 2: Bounded range search
dups = [5, 10, 5, 20, 5]
assert dups.index(5) == 0
assert dups.index(5, 1) == 2
assert dups.index(5, 3) == 4
# Test 3: ValueError on missing item
missing_ok = False
try:
data.index("omega")
except ValueError:
missing_ok = True
assert missing_ok is True
# Test 4: Enumerate all occurrences
indices = [i for i, x in enumerate(dups) if x == 5]
assert indices == [0, 2, 4]
print("All list.index() unit assertions successfully verified!")Terminal Output:
All list.index() unit assertions successfully verified!
Returning -1 in Python would represent the last element via negative indexing. Raising ValueError prevents accidental silent bugs.
The end parameter is strictly exclusive. The search examines indices up to end - 1.
Use list comprehension with enumerate(): [i for i, x in enumerate(lst) if x == target].
list.index() performs a linear search, giving it an O(N) worst-case time complexity.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.