БэкендPython

IndexError: list index out of range в Python: почему индекс вышел за границы списка

Разбираем IndexError: list index out of range: допустимые индексы, пустые списки, ошибки в циклах и безопасные способы получить элемент.

Кодик

Автор

6 мин чтения

IndexError: list index out of range появляется, когда код просит элемент по позиции, которой в последовательности нет. Для списка длины 3 допустимы индексы 0, 1, 2 и отрицательные -1, -2, -3. Исправление начинается не с try, а с двух значений: len(items) и фактического индекса. Затем нужно понять, почему алгоритм создал недопустимую позицию или почему список оказался пустым.

Индекс является адресом элемента внутри последовательности. В Python нумерация начинается с нуля, поэтому последний положительный индекс всегда на единицу меньше длины. Ошибка особенно часто возникает после фильтрации, при чтении первой строки файла, в цикле с ручным счётчиком и при обращении к результату поиска, который ничего не вернул.

1Длина

len(items) сообщает количество элементов прямо перед ошибкой.

2Индекс

repr(index) показывает позицию, которую запросил код.

3Источник

Нужно проверить, кто сформировал список и почему его размер изменился.

Какие индексы действительно существуют

У списка из четырёх элементов положительные позиции идут от 0 до 3. Отрицательная нумерация идёт справа: -1 означает последний элемент, а -4 первый. Значения 4 и -5 уже находятся вне диапазона. Срезы ведут себя иначе: Python обрезает слишком широкие границы среза, поэтому items[:100] не вызывает IndexError.

colors = ['red', 'green', 'blue']

print(colors[0])   # red
print(colors[2])   # blue
print(colors[-1])  # blue
print(colors[3])   # IndexError: list index out of range
ВыражениеРезультат при длине 3Почему
items[0]Первый элементНумерация начинается с нуля
items[2]Последний элементМаксимум равен len(items) - 1
items[-1]Последний элементОтрицательный индекс идёт справа
items[3]IndexErrorТакой позиции уже нет
items[:100]Весь списокГраница среза безопасно обрезается

Допустимые положительные и отрицательные индексы списка Python
Для длины 3 крайние допустимые позиции равны 2 и -3.

Печатайте состояние прямо перед доступом. Добавьте print(len(items), index, repr(items)) перед проблемной строкой. Значения после ошибки уже недоступны, а значения задолго до неё могли измениться. Для большого списка выводите первые элементы и длину, чтобы не потерять важную строку в шуме.

Почему ошибка часто возникает в цикле

Проверьте границы цикла
  1. Найдите строку с квадратными скобками из последнего кадра Traceback.
  2. Запишите длину списка перед началом цикла.
  3. Сравните последнее значение счётчика с len(items) - 1.
  4. Проверьте, не удаляются ли элементы во время обхода.
  5. Если нужен только элемент, итерируйтесь по значениям без индексов.
  6. Если нужны позиция и элемент, используйте enumerate.

Конструкция range(len(items) + 1) делает лишнюю итерацию. Когда длина равна 3, range(4) выдаёт 0, 1, 2, 3, но индекс 3 не существует. Ещё опаснее менять список внутри цикла: после удаления длина уменьшается, а счётчик продолжает расти по старому плану.

tasks = ['код', 'тесты', 'деплой']

# Индекс вообще не нужен
for task in tasks:
    print(task)

# Если нужна позиция
for index, task in enumerate(tasks):
    print(index, task)

Безопасный выбор способа обхода списка Python
Прямой for и enumerate убирают ручной расчёт границ в большинстве циклов.

Лучший безопасный индекс тот, который не пришлось вычислять

Перебор for item in items исключает ошибку границы для обычного обхода. enumerate(items) добавляет корректную позицию. Ручной range оставляйте для алгоритмов, где индекс участвует в вычислении соседей или шага.

Пустой список и доступ к первому или последнему элементу

Выражения items[0] и items[-1] одинаково падают на пустом списке. Это часто происходит после фильтра: исходные данные были, но ни один элемент не прошёл условие. Перед доступом определите контракт: пустой результат является нормальной ситуацией, ошибкой данных или сигналом использовать значение по умолчанию.

ЗадачаБезопасный вариантКогда применять
Взять первый элемент или Noneitems[0] if items else NoneПустой результат допустим
Взять последний элементitems[-1] if items else NoneНужно явно обработать отсутствие
Получить первый подходящийnext((x for x in items if ok(x)), None)Поиск может ничего не найти
Проверить конкретный индекс0 <= i < len(items)Индекс приходит извне
Удалить последнийitems.pop() if items else NoneПустой стек является ожидаемым
scores = [42, 67, 88]
passed = [score for score in scores if score >= 90]

if passed:
    print('Лучший результат:', passed[-1])
else:
    print('Результатов от 90 пока нет')

Безопасная обработка пустого списка перед доступом к элементу
Сначала определите, является ли пустой результат нормальным сценарием или ошибкой данных.

Проверка длины должна быть рядом с использованием. Не полагайтесь на то, что список был непустым в начале функции. Между проверкой и доступом код мог отфильтровать или удалить элементы. Чем ближе условие к квадратным скобкам, тем проще доказать корректность диапазона.

Исправления, которые скрывают причину

Перехват IndexError допустим, если отсутствие элемента является частью протокола, но обычно условие читается яснее. Если индекс рассчитывается неверно, except превращает ошибку алгоритма в молчаливое пропускание данных. Сначала подтвердите ожидаемый диапазон, затем выбирайте обработку.

Добавлять единицу к len

range(len(items) + 1) создаёт лишний индекс, а не включает последний элемент.

Удалять элементы во время обхода

Длина и позиции меняются. Создайте новый список или обходите копию.

Ловить любой IndexError

Внутри блока могла упасть другая последовательность. Проверяйте конкретное условие заранее.

Подставлять индекс 0

Это убирает падение, но может вернуть неверный элемент и повредить логику.

Диагноз должен содержать длину и недопустимый индекс

Фраза «список имел длину 0 после фильтра, а код запросил индекс -1» полезнее, чем «сломался список». Она показывает, какое условие добавить и где искать источник пустого результата.

Практика: исправляем выбор участника

Представьте список игроков и номер места, введённый человеком. Пользователь считает места с единицы, Python индексы с нуля. Нужно проверить ввод, преобразовать номер в индекс и только затем обращаться к списку. Так одна проверка закрывает пустой список, слишком большое число и отрицательный ввод.

Готовый порядок проверки
  1. Получите номер как строку и убедитесь, что он является целым числом.
  2. Преобразуйте пользовательское место в индекс выражением place - 1.
  3. Проверьте условие 0 <= index < len(players).
  4. Выведите понятное сообщение, если места нет.
  5. Проверьте места 1, последнее, 0 и число больше длины.
  6. Снова запустите исходный сценарий, который давал IndexError.
Граница пользователя и граница Python различаются. Если интерфейс показывает позиции от 1, преобразование должно происходить один раз на входе. Не смешивайте пользовательские номера и индексы в разных частях программы: дайте переменным разные имена place и index.
Короткие ответы
Какой последний индекс у списка длины 5?

Положительный индекс 4. Выражение items[5] уже выйдет за границы.

Почему items[-1] падает на пустом списке?

Отрицательная нумерация работает только для существующих элементов. В пустой последовательности последнего элемента нет.

Почему срез items[:100] не падает?

Python обрезает границы среза до допустимого диапазона, в отличие от доступа к одному индексу.

Чем заменить range(len(items))?

Для значений используйте прямой for, а для позиции и значения вместе используйте enumerate.

Всегда ли нужно ловить IndexError?

Нет. Для ожидаемой проверки диапазона обычно яснее условие. Перехват нужен, когда ошибка действительно является частью выбранного протокола.

Научитесь видеть состояние списка до ошибки

Закрепите списки и циклы в курсе Python, затем разберите материал о списках как первой суперсиле. Для чтения файла и номера строки пригодится статья про частые ошибки новичков.

Если ошибка появляется в длинной цепочке функций, используйте порядок из инструкции по запуску и проверке Python-скрипта. В Кодике сохраните входные данные, длину и индекс: по этим трём фактам причина обычно видна сразу.