Что означает ошибка 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
Делаем форму обратной связи на сайте
Делаем форму обратной связи на сайте

Говорят, что если программист может написать форму обратной связи, он может написать всё.

Прокачиваем собственный текстовый редактор
Прокачиваем собственный текстовый редактор
medium
Что такое yield в Python и как его использовать
Что такое yield в Python и как его использовать

Большая история про генераторы и итераторы

hard
ООП: атрибуты и методы
ООП: атрибуты и методы

Два главных слова любого программиста в ООП. Знай их, люби их, говори правильно.

easy
Пинг-понг на JavaScript
Пинг-понг на JavaScript

Да, вдвоём тоже можно.

easy
Аналитика данных на практике: DC против Marvel
Аналитика данных на практике: DC против Marvel

Кто круче: Джокер или Железный Человек?

hard
easy