Ситуация: у нас есть проект, в котором мы математически моделируем игру в рулетку. Мы хотим обработать отдельно нечётные числа, которые есть на рулетке, — для этого нам нужно выбросить из списка все чётные. Проверка простая: если число делится на 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 до 36.
- Организовали цикл, который зависит от длины списка и на первом шаге получает его размер.
- Внутри цикла проверяем на чётность, и если чётное — удаляем число из списка.
- Фактический размер списка меняется, а цикл держит в голове старый размер, который больше.
- Когда мы по старой длине списка обращаемся к очередному элементу, то выясняется, что список закончился и обращаться уже не к чему.
- Компьютер останавливается и выводит ошибку.
Что делать с ошибкой 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])