Sitelet https://www.askpython.com/python/list/indexing-in-python

How to Use Index in Python

Working with Python data often means reading a known position or finding where a value appears. Indexing uses square brackets to read by position, and index() searches for a matching value.

This article shows how those operations differ and how to use enumerate() when a loop needs both an item and its position.

TL;DR: Use Brackets to Read and index() to Search

Use square brackets with an integer to retrieve a sequence item, and call list.index(value) to find the first matching value. Negative indexes count from the end, while slices select a range without changing the original list.

  • The first sequence position is 0.
  • list.index() returns the first match and raises ValueError when none exists.
  • Use enumerate() when a loop needs both an item and its position.

What Does Indexing Mean in Python?

Lists, tuples and strings use zero-based integer positions. Dictionaries use keys instead. For example, colors[1] reads the second item, while colors.index(“blue”) searches for the first item equal to blue.

The Python sequence documentation defines the shared indexing and slicing behavior. Someone learning Python from scratch can practice by making a short list, printing one position, then changing the position and observing which item appears.

How to Use Indexing in Python Step by Step

The example starts with four values, so the same list also supports a later search for repeated items.

Step 1: Read an item by position

Put a zero-based integer inside square brackets. If it is outside the sequence’s valid positions, Python raises IndexError.

items = ["red", "blue", "green", "blue"]
print(items[1])

The program prints:

blue

The example prints blue, the value stored at position 1.

Step 2: Search for a value with index()

list.index(value) returns the first matching position. Optional start and stop arguments limit the search, and stop is excluded.

For example, a program can locate a selected name before replacing or removing it. This search also works when an earlier edit has changed where the name appears.

Use enumerate() with a condition to collect every matching position. Repeated index() calls need an advancing start argument, while a filtered list comprehension can collect positions when that is all you need.

items = ["red", "blue", "green", "blue"]
print(items.index("blue"))
print(items.index("blue", 2))

The output is:

1
3

The second call passes 2 as its start argument.

Step 3: Count backward with a negative index

A negative index counts from the sequence’s end, with -1 selecting the final item. This avoids calculating the final positive index when only a tail item matters.

items = ["red", "blue", "green", "blue"]
print(items[-1])

The output is:

blue

There is no -0 position. Avoid this access when the sequence may be empty, since no final item exists.

Step 4: Select a range with a slice

A slice uses sequence[start:stop] to return items from start up to, but not including, stop. It creates a new list for list slices and leaves the source list unchanged.

items = ["red", "blue", "green", "blue"]
print(items[1:3])

The output is:

['blue', 'green']

Omitting a bound uses the sequence end on that side. A third slice value sets a step, which can skip items or traverse a sequence backward.

Step 5: Get each position in a loop

Use enumerate(sequence) when each loop pass needs both a position and its item. It avoids maintaining a separate counter by hand.

items = ["red", "blue", "green", "blue"]
for position, item in enumerate(items):
    print(position, item)

The output is:

0 red
1 blue
2 green
3 blue

The reader-facing example is in this terminal capture. I ran the full sequence as python3 indexing_demo.py. Its output is shown together in the capture, including both matching positions and each enumerate() pair.

Python indexing demo showing positions and matching values

index() Syntax and Parameters

Call index() on a sequence when you know a value and need its position. The method returns an integer for the first equal item in the selected search range.

sequence.index(value, start, stop)
ArgumentMeaningExample
valueRequired value to locateitems.index(“blue”)
startOptional starting position, inclusiveitems.index(“blue”, 2)
stopOptional ending position, exclusiveitems.index(“blue”, 0, 3)

The optional bounds work like a slice range: start is included and stop is excluded. They narrow the search without returning a sliced copy. The result remains an index into the original sequence, so it can be used for bracket access.

Choose a bounded search when the relevant portion is known, such as checking entries after a marker. Omitting both bounds searches the entire sequence. A value outside the selected range raises ValueError even if it appears elsewhere.

Bracket syntax has a different job. Write sequence[position] to retrieve one item, or sequence[start:stop:step] to retrieve a range. The position must be an integer, while slice bounds may be omitted to use the sequence boundary.

More Python Indexing Examples

Python uses the same bracket syntax across ordered sequences. A tuple returns the item at a position, and a string returns a one-character string. Both follow the same rules for slices.

point = (12, 8)
word = "python"
print(point[0])
print(word[2:5])

This prints 12 and tho on separate lines. A tuple and a string are immutable, so indexing can read their contents but cannot assign to a selected position.

For instance, point[0] = 4 raises TypeError because a tuple does not support item assignment. If a program needs to update a value, create a new tuple or use a mutable list instead.

A slice is useful when the task concerns a segment rather than one position. The stop position is left out, which makes adjacent slices fit together without overlap.

letters = ["a", "b", "c", "d", "e"]
print(letters[:2])
print(letters[2:])
print(letters[::2])

Adjacent slices use a shared boundary without repeating that item, and a step selects items at regular intervals from the slice’s first position.

When a loop needs a matching value and its position, enumerate() keeps those pieces together. Its optional start argument changes the first number it yields, which is useful when numbering a section from one rather than zero.

for number, item in enumerate(["draft", "review"], start=1):
    print(number, item)

The output is 1 draft and 2 review. The start parameter changes the numbers produced by enumerate(), not the positions used to index a Python list.

Indexing a dictionary uses a key rather than a numeric sequence position. For a mapping like user = {“name”: “Asha”}, user[“name”] retrieves the value stored under that key. A missing key raises KeyError, so use get() when a default value is appropriate.

These distinctions help choose an operation: bracket indexing retrieves a known slot, index() searches for a value, enumerate() pairs items with positions during iteration, and a slice returns a range. Selecting by the information already available avoids searching when the position is known.

Before accessing a position calculated from user input, compare it with the sequence length. A length of zero means there is no valid item to retrieve. For a nonempty sequence, valid positive positions begin at zero and end one less than len(sequence).

items = ["oak", "pine"]
position = 1
if 0 <= position < len(items):
    print(items[position])

This check protects positive positions from going past the end. If negative positions are allowed as input, decide whether they should count backward or be rejected, then validate that policy explicitly.

Equality compares values, while identity asks whether two references point to the same object. list.index() uses equality to locate a value. A custom object can therefore match a different object instance when their equality rules say the values are equal.

When a list contains duplicates, index() returns the first equal item at or after the starting bound. To process every match, enumerate() provides each position while the loop checks its item. This keeps the original positions available without repeatedly searching from the beginning.

Slice bounds are forgiving: a bound beyond the sequence is clipped to its boundary, and a slice can return an empty sequence. Bracket access is stricter and raises IndexError for an invalid position. Use slicing when an empty result is acceptable, and check bounds before requesting one exact item.

Common errors with indexing

Python sequences raise IndexError for an invalid position, while list.index() raises ValueError when its search has no match. These cases need different fixes.

Use bracket access when the slot is known, such as the second field in a fixed-format row, and search by value when the content is known but its position can change.

For repeated matches, returning one position may not answer the question. The loop approach is useful when the program must act on each matching element as it finds it. A comprehension is compact when the result should be a new list of positions for later use.

CaseSymptomFix
Repeated valueindex() returns only its first matchUse enumerate() with a condition to collect positions
Missing valueindex() raises ValueErrorCheck membership with in, or catch ValueError
Out-of-range positionBracket access raises IndexErrorCheck the sequence length before access
Dictionary lookupInteger is treated as a key, not a sequence positionUse the intended key, such as record["name"]

Strings and tuples also support bracket indexing and slices, but they cannot be changed in place. The dedicated Python index() method guide covers list searches in more detail, and the negative indexing guide focuses on counting from the end.

Checking membership before calling index() is clear for occasional lookups, but it scans the list twice. Catching ValueError searches once and fits when absence is an ordinary outcome handled by the caller.

Conclusion

Choose an operation based on the information available: a position, a value, or a need to visit every item. Check bounds for positional access and handle absent values in a search.

For the full method behavior, see the Python list documentation and AskPython’s guides to list.index() and negative indexes.

FAQ

These answers cover common choices when working with indexes.

Does index() return every matching position?

No. Use enumerate() with a condition to collect all matching positions.

Can dictionaries be indexed by position?

Dictionaries are accessed by keys, such as record[“name”], rather than by sequence position.

What happens when list.index() cannot find a value?

It raises ValueError. Check membership with in first or catch ValueError when absence is an expected case.

Amit Mandal
Amit Mandal
Articles: 4