Tu as raison! 'example'[3:4]
et 'example'[3]
sont fondamentalement différents, et le découpage en dehors des limites d'une séquence (au moins pour les éléments intégrés) ne provoque pas d'erreur.
Cela peut paraître surprenant au début, mais c'est logique quand on y pense. L'indexation renvoie un seul élément, mais le découpage renvoie une sous-séquence d'éléments. Ainsi, lorsque vous essayez d'indexer une valeur inexistante, il n'y a rien à retourner. Mais lorsque vous découpez une séquence en dehors des limites, vous pouvez toujours renvoyer une séquence vide.
Une partie de ce qui est déroutant ici est que les chaînes se comportent un peu différemment des listes. Regardez ce qui se passe lorsque vous faites la même chose sur une liste:
>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]
Ici, la différence est évidente. Dans le cas des chaînes, les résultats semblent identiques car en Python, il n'existe pas de caractère individuel en dehors d'une chaîne. Un seul caractère est juste une chaîne de 1 caractère.
(Pour la sémantique exacte du découpage en dehors de la plage d'une séquence, voir la réponse de mgilson .)
[999:9999]
n'est pas un index, c'est une tranche et a une sémantique différente. Extrait de l'intro de python: "Les indices de tranche dégénérée sont gérés avec élégance: un index trop grand est remplacé par la taille de la chaîne, une limite supérieure plus petite que la limite inférieure renvoie une chaîne vide."