Вы правы! 'example'[3:4]
и 'example'[3]
принципиально отличаются, и нарезка за пределы последовательности (по крайней мере, для встроенных модулей) не вызывает ошибки.
Поначалу это может показаться удивительным, но, если подумать, это имеет смысл. Индексирование возвращает один элемент, а разрезание возвращает подпоследовательность элементов. Поэтому, когда вы пытаетесь проиндексировать несуществующее значение, возвращать нечего. Но когда вы нарезаете последовательность за пределами границ, вы все равно можете вернуть пустую последовательность.
Отчасти сбивает с толку то, что строки ведут себя немного иначе, чем списки. Посмотрите, что происходит, когда вы делаете то же самое со списком:
>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]
Здесь разница очевидна. В случае строк результаты кажутся идентичными, потому что в Python нет такой вещи, как отдельный символ вне строки. Одиночный символ - это просто строка из 1 символа.
(Точную семантику нарезки вне диапазона последовательности см. В ответе Мильсона .)
[999:9999]
не индекс, это срез и имеет другую семантику. Из вступления к python: «Вырожденные индексы срезов обрабатываются изящно: слишком большой индекс заменяется размером строки, верхняя граница меньше нижней возвращает пустую строку».