IndexError: list index out of range появляется, когда код просит элемент по позиции, которой в последовательности нет. Для списка длины 3 допустимы индексы 0, 1, 2 и отрицательные -1, -2, -3. Исправление начинается не с try, а с двух значений: len(items) и фактического индекса. Затем нужно понять, почему алгоритм создал недопустимую позицию или почему список оказался пустым.
Индекс является адресом элемента внутри последовательности. В Python нумерация начинается с нуля, поэтому последний положительный индекс всегда на единицу меньше длины. Ошибка особенно часто возникает после фильтрации, при чтении первой строки файла, в цикле с ручным счётчиком и при обращении к результату поиска, который ничего не вернул.
len(items) сообщает количество элементов прямо перед ошибкой.
repr(index) показывает позицию, которую запросил код.
Нужно проверить, кто сформировал список и почему его размер изменился.
Какие индексы действительно существуют
У списка из четырёх элементов положительные позиции идут от 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] | Весь список | Граница среза безопасно обрезается |

Для длины 3 крайние допустимые позиции равны 2 и -3.
print(len(items), index, repr(items)) перед проблемной строкой. Значения после ошибки уже недоступны, а значения задолго до неё могли измениться. Для большого списка выводите первые элементы и длину, чтобы не потерять важную строку в шуме.Почему ошибка часто возникает в цикле
- Найдите строку с квадратными скобками из последнего кадра Traceback.
- Запишите длину списка перед началом цикла.
- Сравните последнее значение счётчика с
len(items) - 1. - Проверьте, не удаляются ли элементы во время обхода.
- Если нужен только элемент, итерируйтесь по значениям без индексов.
- Если нужны позиция и элемент, используйте
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)
Прямой for и enumerate убирают ручной расчёт границ в большинстве циклов.
Перебор for item in items исключает ошибку границы для обычного обхода. enumerate(items) добавляет корректную позицию. Ручной range оставляйте для алгоритмов, где индекс участвует в вычислении соседей или шага.
Пустой список и доступ к первому или последнему элементу
Выражения items[0] и items[-1] одинаково падают на пустом списке. Это часто происходит после фильтра: исходные данные были, но ни один элемент не прошёл условие. Перед доступом определите контракт: пустой результат является нормальной ситуацией, ошибкой данных или сигналом использовать значение по умолчанию.
| Задача | Безопасный вариант | Когда применять |
|---|---|---|
| Взять первый элемент или None | items[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 превращает ошибку алгоритма в молчаливое пропускание данных. Сначала подтвердите ожидаемый диапазон, затем выбирайте обработку.
range(len(items) + 1) создаёт лишний индекс, а не включает последний элемент.
Длина и позиции меняются. Создайте новый список или обходите копию.
Внутри блока могла упасть другая последовательность. Проверяйте конкретное условие заранее.
Это убирает падение, но может вернуть неверный элемент и повредить логику.
Фраза «список имел длину 0 после фильтра, а код запросил индекс -1» полезнее, чем «сломался список». Она показывает, какое условие добавить и где искать источник пустого результата.
Практика: исправляем выбор участника
Представьте список игроков и номер места, введённый человеком. Пользователь считает места с единицы, Python индексы с нуля. Нужно проверить ввод, преобразовать номер в индекс и только затем обращаться к списку. Так одна проверка закрывает пустой список, слишком большое число и отрицательный ввод.
- Получите номер как строку и убедитесь, что он является целым числом.
- Преобразуйте пользовательское место в индекс выражением
place - 1. - Проверьте условие
0 <= index < len(players). - Выведите понятное сообщение, если места нет.
- Проверьте места 1, последнее, 0 и число больше длины.
- Снова запустите исходный сценарий, который давал IndexError.
place и index.Какой последний индекс у списка длины 5?
Положительный индекс 4. Выражение items[5] уже выйдет за границы.
Почему items[-1] падает на пустом списке?
Отрицательная нумерация работает только для существующих элементов. В пустой последовательности последнего элемента нет.
Почему срез items[:100] не падает?
Python обрезает границы среза до допустимого диапазона, в отличие от доступа к одному индексу.
Чем заменить range(len(items))?
Для значений используйте прямой for, а для позиции и значения вместе используйте enumerate.
Всегда ли нужно ловить IndexError?
Нет. Для ожидаемой проверки диапазона обычно яснее условие. Перехват нужен, когда ошибка действительно является частью выбранного протокола.
Закрепите списки и циклы в курсе Python, затем разберите материал о списках как первой суперсиле. Для чтения файла и номера строки пригодится статья про частые ошибки новичков.
Если ошибка появляется в длинной цепочке функций, используйте порядок из инструкции по запуску и проверке Python-скрипта. В Кодике сохраните входные данные, длину и индекс: по этим трём фактам причина обычно видна сразу.