Что означает ошибка IndexError: list index out of range

Многогранная ошибка с коварным поведением.

Что означает ошибка IndexError: list index out of range

Ситуация: у нас есть проект, в котором мы математически моделируем игру в рулетку. Мы хотим обработать отдельно нечётные числа, которые есть на рулетке, — для этого нам нужно выбросить из списка все чётные. Проверка простая: если число делится на 2 без остатка — оно чётное и его можно удалить. Для этого пишем такой код:

# в рулетке — 36 чисел, не считая зеро
numbers = [n for n in range(36)]
# перебираем все числа по очереди
for i in range(len(numbers)):
    # если текущее число делится на 2 без остатка
    if numbers[i] % 2 == 0:
        # то убираем его из списка
        del numbers[i]

Но при запуске компьютер выдаёт ошибку:

❌ IndexError: list index out of range

Почему так произошло, ведь мы всё сделали правильно?

Что это значит: компьютер на старте цикла получает и запоминает одну длину списка с числами, а во время выполнения эта длина меняется. Компьютер, держа в памяти старую длину, пытается обратиться по номерам к тем элементам, которых уже нет в списке. 

Когда встречается: когда программа одновременно использует список как основу для цикла и тут же в цикле добавляет или удаляет элементы списка.

В нашем примере случилось вот что:

  1. Мы объявили список из чисел от 1 до 36.
  2. Организовали цикл, который зависит от длины списка и на первом шаге получает его размер.
  3. Внутри цикла проверяем на чётность, и если чётное — удаляем число из списка.
  4. Фактический размер списка меняется, а цикл держит в голове старый размер, который больше.
  5. Когда мы по старой длине списка обращаемся к очередному элементу, то выясняется, что список закончился и обращаться уже не к чему.
  6. Компьютер останавливается и выводит ошибку.

Что делать с ошибкой IndexError: list index out of range

Основное правило такое: не нужно в цикле изменять элементы списка, если список используется для организации этого же цикла. 

Если нужно обработать список, то результаты можно складывать в новую переменную, например так:

# в рулетке — 36 чисел, не считая зеро
numbers = [n for n in range(36)]
# новый список для нечётных чисел
new_numbers = []
# перебираем все числа по очереди
for i in range(len(numbers)):
    # если текущее число не делится на 2 без остатка
    if numbers[i] % 2 != 0:
        # то добавляем его в новый список
        new_numbers.append(numbers[i])

Художник:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Вам может быть интересно
$ is not defined в jQuery: что это значит и что делать
$ is not defined в jQuery: что это значит и что делать
medium
ReferenceError: math is not defined — что это означает
ReferenceError: math is not defined — что это означает

Противная и неочевидная ошибка, которую очень легко исправить.

medium
Uncaught TypeError: Cannot read property — что это означает
Uncaught TypeError: Cannot read property — что это означает

Нельзя прочитать то, чего нет.

medium
Запускаем свой сайт на движке Publii
Запускаем свой сайт на движке Publii

Он работает на компьютере даже без интернета

easy
Делаем свой текстовый редактор с автосохранением
Делаем свой текстовый редактор с автосохранением

Это не так сложно, как звучит.

medium
Что означает ошибка SyntaxError: unlabeled break must be inside loop or switch
Что означает ошибка SyntaxError: unlabeled break must be inside loop or switch

Нельзя выйти из цикла, если его нет

easy
Проект: эффектно переключаем картинки на странице
Проект: эффектно переключаем картинки на странице

Как в бумажном журнале

easy
Решаем задачу Эйнштейна перебором (и программированием)
Решаем задачу Эйнштейна перебором (и программированием)

Проверим 24 миллиарда комбинаций, почти не задействуя мозг

easy
Как подключить фотогалерею к сайту
Как подключить фотогалерею к сайту

Рецепт на 6 минут.

easy
easy