IndexError en Python : d'où vient l'erreur et comment la corriger

IndexError signale un accès à un rang qui n'existe pas dans une liste, un tuple ou une chaîne : la séquence est plus courte que prévu.
5 min de lecture
Believemy logo

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.

PYTHON
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 range

Le 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.

Bon à savoir

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.

ÉcritureCe qu'elle apporte
Parcourir avec forAucun rang à manipuler, donc aucun dépassement possible
Tester la longueur avantif liste: suffit à écarter le cas vide
Découper plutôt qu'accéderliste[: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.

Attention

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

Question

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.

Question

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.

Question

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.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.