Python IndexError: Negative Index Out of Range (2026)

Python’s negative indices (lst[-1] = last item) are convenient but can still raise IndexError if the negative index is more negative than the list length. [1, 2][-5] raises just like [1, 2][5] does. Here is how negative indexing actually works and 4 safe patterns.

Python IndexError Negative Index Out of Range (2026)

How negative indexing works under the hood

lst = ['a', 'b', 'c']
# Python converts negative index to positive: lst[-i] becomes lst[len(lst) - i]
# So lst[-1] = lst[3-1] = lst[2] = 'c'
# And lst[-5] = lst[3-5] = lst[-2] which is also negative, so it tries lst[3+(-2)] = lst[1]
# Wait, no: negative becomes positive ONCE. -5 becomes 3 - 5 = -2, still negative, raises IndexError
print(lst[-5])  # IndexError: list index out of range

Minimal reproducer

def last_n(lst, n):
    return lst[-n]  # IndexError if n > len(lst)

last_n([1, 2, 3], 5)  # IndexError: list index out of range

Fix 1: Bounds check on negative

def safe_nth_from_end(lst, n):
    if n > len(lst):
        return None  # or raise a clearer error
    return lst[-n]

Fix 2: Use slicing (never raises)

lst = [1, 2, 3]
last_one = lst[-1:]    # [3] - safe even if empty
last_five = lst[-5:]   # [1, 2, 3] - safe, returns what is available

Fix 3: max(0, …) to clamp

def take_last(lst, n):
    return lst[max(0, len(lst) - n):]
# take_last([1,2,3], 5) returns [1,2,3]
# take_last([1,2,3,4,5], 2) returns [4, 5]

Fix 4: itertools.islice for streams

from collections import deque
# For an iterator that does not support len(), keep a sliding window
last_3 = deque(maxlen=3)
for item in some_stream():
    last_3.append(item)
# last_3 now always has the most recent 3 items, never raises

Negative index rules of thumb

ExpressionResult
[1,2,3][-1]3 (last)
[1,2,3][-3]1 (first, valid)
[1,2,3][-4]IndexError (too negative)
[][-1]IndexError (empty list)
[1,2,3][-1:][3] (slicing, safe)
[][-1:][] (slicing, safe)

Frequently Asked Questions

Why does Python support negative indices at all?

For convenient access to the end of a sequence without computing length first. lst[-1] is more readable than lst[len(lst)-1]. It also enables clean slicing like lst[-3:] for “last 3 items.” The behavior is borrowed from R and several functional languages.

Why does negative slicing never raise but negative indexing does?

Slicing is “give me whatever is in this range, clamp if needed” (returns empty if nothing). Indexing is “give me exactly this element, fail if missing.” The slice/index distinction is consistent across all sequence types in Python (list, tuple, str, bytes, range, NumPy array).

Is there a way to get a default value instead of IndexError on negative index?

No built-in equivalent of dict.get() for lists. Common patterns: (lst[-n:] or [None])[0] for the nth-from-end with None default, or lst[-n] if n <= len(lst) else default. Or wrap in your own safe_get function.

Do dicts use negative indices?

No. dict keys are arbitrary hashable objects, not ordered positions. d[-1] looks for a key with value -1. To access the “last inserted” key (Python 3.7+ preserves insertion order), use list(d.keys())[-1] or next(reversed(d)).

Are negative indices slower than positive ones?

In CPython, both have identical O(1) cost for lists. The negative-to-positive conversion is a single subtraction. No measurable performance difference. Use whichever reads more clearly.

Leave a Comment