Définition
Une séquence a une longueur, et le code qui la lit fait une hypothèse sur cette longueur. Tant que les deux s'accordent, personne ne remarque rien. Le jour où la liste est plus courte que prévu, Python a le choix entre inventer une valeur et refuser. Il refuse, et ce refus porte un nom : IndexError.
L'erreur survient donc dès qu'un élément est demandé à un rang qui n'existe pas. Les rangs commencent à zéro, ce qui décale tout d'une unité par rapport au comptage courant : une liste de trois éléments accepte les rangs 0, 1 et 2, et refuse le 3, qui désignerait un quatrième élément.
couleurs = ["rouge", "vert", "bleu"]
# Trois éléments, donc trois rangs valides : 0, 1 et 2.
couleurs[2] # "bleu", le dernier de la liste
# Le rang 3 pointerait vers un quatrième élément, qui n'existe pas.
couleurs[3]
# IndexError: list index out of rangeLe message est littéral : le rang demandé sort de l'intervalle existant, qui va de zéro à len(liste) - 1. Rien à décoder, donc, et l'enquête tient dans une question : pourquoi la séquence est-elle plus courte que prévu ?
La règle vaut pour tout ce qui se parcourt par rang : listes, tuples, chaînes. Les dictionnaires, eux, lèvent une KeyError, puisqu'ils fonctionnent par clé et non par position. Savoir laquelle s'affiche indique déjà sur quel objet la ligne fautive travaille.
Une IndexError peut apparaître sans qu'aucun rang ne soit écrit : liste.pop() sur une liste vide lève la même erreur, avec le message pop from empty list. La méthode retire le dernier élément, et une liste vide n'en a aucun.
Les trois situations classiques
Presque toutes les IndexError viennent de trois scénarios, et les reconnaître fait gagner du temps : chacun se corrige ailleurs dans le programme.
Le premier est le décalage d'une unité, la fameuse erreur de bord. Il vient du réflexe de compter les éléments, puis d'écrire le rang comme si le comptage commençait à un. Parcourir avec range(len(liste) + 1) ou écrire liste[len(liste)] dépasse d'exactement un rang. C'est l'argument le plus solide en faveur de la boucle for directe, qui ne peut pas dépasser puisqu'elle ne compte rien : la séquence se déroule d'elle-même.
Le deuxième est la séquence vide. resultats[0] paraît inoffensif, et il l'est tant qu'il reste un élément : le rang zéro n'existe que dans une séquence non vide. Sur une recherche qui n'a rien trouvé, la même ligne lève une IndexError. Ce scénario traverse les tests sans broncher, puis casse en production le jour où le filtre ne retient rien.
Le troisième vient d'un découpage manuel. Un split sur une ligne mal formée renvoie moins de morceaux que prévu, et l'accès au troisième champ échoue sur la seule ligne du fichier qui sort du format. Le programme en traite mille puis s'arrête net, ce qui ressemble à un bug aléatoire. Le traceback désigne la ligne de code, jamais celle du fichier : affichez la valeur découpée juste avant l'accès.
Les trois façons de l'éviter
Trois écritures rendent l'erreur impossible plutôt que de la rattraper. Le tableau les compare, et la troisième mérite quelques explications.
| Écriture | Ce qu'elle apporte |
|---|---|
Parcourir avec for | Aucun rang à manipuler, donc aucun dépassement possible |
| Tester la longueur avant | if liste: suffit à écarter le cas vide |
| Découper plutôt qu'accéder | liste[:3] ne lève rien, même sur une liste plus courte |
Le découpage est en effet tolérant là où l'accès direct est strict. liste[10:20] sur une liste de trois éléments renvoie une liste vide, et liste[:3] renvoie ce qu'il trouve, même sur un seul élément. C'est ce qui rend le slicing pratique pour lire les trois premiers sans connaître le total.
Cette tolérance est aussi un piège. Un rang faux dans un découpage ne lève rien : il produit une liste vide, que la suite du programme traite comme un résultat normal. L'incohérence ressort beaucoup plus loin, sous une forme qui ne ressemble plus à sa cause.
Ce qu'elle dit de vos données
Cette erreur a une qualité rare : elle désigne exactement le problème. Un TypeError peut venir de dix endroits différents, alors qu'un rang hors limites signifie toujours la même chose. La bonne question n'est donc pas comment éviter l'erreur, mais pourquoi cette liste est plus courte que prévu.
Neuf fois sur dix, la réponse se trouve en amont : un filtre qui a tout écarté, un fichier dont la dernière ligne est vide, une requête sans résultat. Le plus rapide est d'afficher la longueur juste avant l'accès. Si elle vaut zéro, le vrai problème se situe là où la séquence a été construite.
Enfermer l'accès dans un try sans répondre à cette question ne fait que déplacer le symptôme : le programme continue avec une donnée manquante, qui ressortira plus tard. Attraper l'erreur garde son sens quand le cas vide est prévu.
Questions fréquentes
Que signifie un rang négatif ?
Il compte depuis la fin : liste[-1] désigne le dernier élément et liste[-2] l'avant-dernier, ce qui évite de recalculer la longueur. La règle du dépassement ne change pas : sur trois éléments, les rangs négatifs s'arrêtent à -3, et liste[-4] lève bien une IndexError.
Comment accéder à un élément sans risquer l'erreur ?
Par un découpage, qui renvoie une liste vide plutôt que de lever, ou par un try suivi d'un except qui prévoit le cas vide. Les séquences n'ont pas d'équivalent du get des dictionnaires, faute de valeur par défaut raisonnable.
Pourquoi mon code fonctionne-t-il en local et pas en production ?
Parce que les données réelles contiennent un cas absent du jeu de test : une ligne vide en fin de fichier, un champ manquant, une recherche sans résultat. Le code n'a pas changé, la forme des données oui. D'où l'intérêt d'un test sur la collection vide.