En Python, une liste est un objet mutable ordonné, modifiable en place par ajout, suppression ou réaffectation d’éléments. La majorité des bugs liés aux listes ne proviennent pas d’une méconnaissance de la structure elle-même, mais d’un mauvais ordre des vérifications avant l’accès aux éléments.
Tester la taille d’une liste après avoir tenté d’y accéder par indice, ignorer le scope d’une variable de boucle ou avaler une exception sans la traiter sont des erreurs qui reviennent dans presque tous les projets débutants.
Lire également : Install py-pip : erreurs les plus fréquentes et comment les corriger rapidement
Ordre des vérifications sur une liste Python : la source cachée des IndexError
Le réflexe le plus courant consiste à accéder directement à un indice, puis à vérifier ensuite si l’opération était légitime. Ce schéma inversé provoque des IndexError silencieuses dans les cas limites.
Prenons un cas concret issu de cours universitaires : une fonction doit renvoyer les deux premiers et deux derniers caractères d’une chaîne, ou une chaîne vide si la longueur est inférieure à deux. Le code suivant semble logique au premier regard :
A lire également : UHA e Service : les erreurs les plus fréquentes... et comment les éviter
def func(chaine): resultat = chaine[0]+chaine[1]+chaine[-2]+chaine[-1] if len(chaine)<2: return "" return resultat
Avec func("BonJOUR"), tout fonctionne. Avec func("B"), Python lève une IndexError: string index out of range avant même d’atteindre le test de longueur. Le problème est identique pour les listes : accéder à ma_liste[3] avant de vérifier que len(ma_liste) > 3 produit exactement le même crash.
La règle est de toujours valider la taille avant tout accès par indice. Inverser ces deux lignes suffit à corriger le bug. Ce principe s’applique partout : lecture de fichiers ligne par ligne, parsing de données JSON, extraction d’éléments depuis une API.

Modifier une liste Python pendant une itération : boucle infinie et éléments manqués
Ajouter ou supprimer des éléments d’une liste tout en itérant dessus avec for est une erreur classique qui produit deux types de dysfonctionnements bien distincts.
Boucle infinie par ajout
Le code suivant illustre le piège :
malist = [1, 2, 3]for i in malist: malist.append(8)
À chaque itération, un élément est ajouté. La liste ne cesse de croître, la boucle ne se termine jamais. Python n’émet aucun avertissement : le programme se fige simplement, et seul un arrêt manuel (KeyboardInterrupt) permet d’en sortir.
Éléments sautés par suppression
Supprimer un élément pendant l’itération décale les indices internes. Le curseur avance d’une position alors qu’un élément vient de disparaître, ce qui fait sauter l’élément suivant. La solution consiste à itérer sur une copie de la liste :
- Utiliser
for item in ma_liste[:]:crée une copie superficielle sur laquelle la boucle itère, pendant que l’original est modifié en toute sécurité. - Construire une nouvelle liste par compréhension (
[x for x in ma_liste if condition]) évite toute mutation et reste plus lisible. - Pour les suppressions conditionnelles complexes, collecter d’abord les indices à supprimer dans une liste séparée, puis les retirer en ordre inverse avec
del.
Argument mutable par défaut : le piège du def avec une liste
Définir une fonction avec une liste comme valeur par défaut est probablement le bug le plus documenté de Python, et pourtant il piège régulièrement des développeurs expérimentés.
def ajouter(element, cible=[]): cible.append(element) return cible
Au premier appel, ajouter("a") renvoie ["a"]. Au deuxième, ajouter("b") renvoie ["a", "b"] au lieu du ["b"] attendu. L’objet liste par défaut est créé une seule fois, au moment de la définition de la fonction, pas à chaque appel. Chaque invocation partage donc la même instance de liste en mémoire.
Le correctif standard utilise None comme sentinelle :
def ajouter(element, cible=None): if cible is None: cible = [] cible.append(element) return cible
Ce patron s’applique à tout objet mutable utilisé comme argument par défaut : dictionnaires, sets, et bien sûr listes.
Scope et exception : deux causes d’erreurs de liste souvent ignorées
Les erreurs de listes sont fréquemment aggravées par une mauvaise gestion du scope ou des exceptions, qui masquent la cause réelle du problème.
Scope des variables dans les list comprehensions
Les list comprehensions gèrent la variable de boucle différemment d’une boucle for classique. Dans une compréhension, la variable reste confinée à l’expression. Dans une boucle for standard, elle persiste après la fin de l’itération et conserve la dernière valeur assignée. Réutiliser le même nom de variable dans les deux contextes crée des bugs subtils où une valeur résiduelle interfère avec le traitement suivant.
Exceptions avalées par un except trop large
Entourer une opération sur liste d’un bloc try/except Exception sans préciser le type d’erreur masque les IndexError, TypeError et ValueError sous un même traitement générique. Le programme continue sans signaler le problème, et le bug se manifeste bien plus loin dans l’exécution.
- Toujours cibler le type d’exception attendu :
except IndexErrorplutôt queexcept Exception. - Utiliser
raise ... from excpour chaîner les exceptions quand une erreur de liste est transformée en erreur métier, afin de conserver la trace de la cause initiale. - Réserver le bloc
finallyau nettoyage de ressources, pas à la logique de traitement des données de la liste.

Tester si une liste est vide : la forme idiomatique Python
Vérifier le contenu d’une liste avec len(ma_liste) == 0 ou ma_liste == [] fonctionne, mais ne correspond pas à l’usage recommandé. La forme idiomatique est if not ma_liste:, qui exploite le fait qu’une liste vide est évaluée comme False dans un contexte booléen.
Cette écriture est plus concise et directement lisible pour tout développeur Python. Elle évite aussi un appel de fonction inutile avec len(). Préférer if not ma_liste à len(ma_liste) == 0 réduit le bruit syntaxique et aligne le code sur les conventions du langage.
La plupart des erreurs liées aux listes Python partagent un trait commun : elles apparaissent non pas au moment de la manipulation de la liste, mais dans le code qui l’entoure. Vérifier la taille avant l’accès, ne jamais modifier une liste pendant son itération, utiliser None comme argument par défaut et cibler précisément les exceptions couvrent la grande majorité des cas rencontrés en production.

