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

IndentationError empêche le fichier de démarrer : en Python, le décalage des lignes délimite les blocs, donc un alignement bancal n'est plus une question de style.
5 min de lecture
Believemy logo

Définition

Vous écrivez une fonction, vous lancez le fichier, et Python refuse de démarrer en parlant de décalage. La logique est bonne, aucun nom n'est mal orthographié : c'est l'alignement des lignes qui coince. Cette situation porte un nom, IndentationError.

Elle surprend surtout ceux qui viennent d'un autre langage. Ailleurs, des accolades disent où un bloc commence et où il finit, et l'indentation ne sert qu'à rendre le tout lisible. Python a retiré les accolades et confié ce rôle au décalage : les espaces en début de ligne ne décorent plus, ils structurent.

Une ligne mal alignée ne rend donc pas le programme moins agréable à lire, elle le rend impossible à interpréter. Python ne peut plus dire à quel bloc elle appartient, et il s'arrête là.

PYTHON
def moyenne(notes):
# le corps devrait être décalé de quatre espaces
total = sum(notes)
return total / len(notes)

# IndentationError: expected an indented block

Cette erreur est un cas particulier de SyntaxError, ce qui décide du moment où la faute est repérée : pendant la lecture du fichier, avant la moindre exécution. Un programme qui en contient une ne démarre donc pas du tout, même si le décalage se cache dans une branche jamais atteinte.


Les trois messages et ce qu'ils veulent dire

Une fois l'erreur affichée, la question est toujours la même : par où commencer ? Le traceback est ici plus bavard que d'habitude. Il ne dit pas seulement qu'un alignement pose problème, il dit lequel, et il n'y a que trois cas.

MessageCe qui s'est passé
expected an indented blockUn deux-points annonce un bloc, et rien n'est décalé en dessous
unexpected indentUne ligne est décalée alors qu'aucun bloc ne l'attendait
unindent does not match any outer indentation levelLe retour en arrière ne retombe sur aucun niveau déjà ouvert

Le premier arrive après un def, un if ou une boucle for laissés vides le temps d'y revenir. Python n'accepte aucun bloc vide : un deux-points exige toujours une ligne décalée en dessous. Le mot-clé pass existe exactement pour réserver cette place sans rien faire.

Le deuxième se répare en une seconde : une ligne a pris quatre espaces d'avance alors qu'aucun deux-points ne lui a ouvert de bloc.

Le troisième déroute davantage. Il signale une sortie de bloc qui retombe entre deux niveaux : le corps était écrit à quatre espaces, la ligne qui le referme en compte deux, et ce niveau n'a jamais été ouvert. Deviner reviendrait à changer le sens du programme, donc Python refuse.

Attention

Le numéro de ligne affiché est celui où Python a constaté le problème, pas toujours celui où il a été commis : sur une sortie de bloc bancale, la ligne fautive est souvent celle du dessus. Vérifiez l'alignement du bloc entier avant de corriger.


Le mélange d'espaces et de tabulations

Reste une cause qui échappe à cette lecture, et c'est la plus pénible : celle qu'on ne voit pas. Deux lignes peuvent sembler alignées à l'écran alors que l'une est décalée par quatre espaces et l'autre par une tabulation. L'éditeur les dessine à la même largeur, Python compte des caractères différents et refuse de trancher : il lève une TabError, qui hérite d'IndentationError.

PYTHON
for ligne in fichier:
    nettoyer(ligne)
	enregistrer(ligne)

# la deuxième ligne commence par une tabulation, pas par des espaces
# TabError: inconsistent use of tabs and spaces in indentation

Le scénario est presque toujours le même : le fichier fonctionnait, puis un copier-coller a glissé une tabulation au milieu des espaces. Réaligner la ligne au jugé donne un résultat qui paraît correct et qui casse ailleurs, puisque la tabulation est toujours là. Demandez plutôt à votre éditeur de convertir toutes les tabulations du fichier en espaces.


Ce qui la fait disparaître définitivement

Corriger l'erreur au cas par cas fonctionne, mais elle revient la semaine suivante. Trois réglages d'éditeur la font disparaître pour de bon.

Quatre espaces par niveau, comme le recommande la PEP 8 : c'est la convention de tout l'écosystème, donc celle de chaque bout de code que vous copierez. La touche de tabulation réglée pour insérer des espaces, ce qui rend le mélange impossible. Et l'affichage des caractères invisibles, le temps de traquer un décalage qui résiste.

Reste une habitude qui vaut tous les réglages : écrire le bloc au moment où vous écrivez la ligne qui l'ouvre. Un if laissé sans corps, un else ajouté après coup, un try dont le contenu viendra plus tard sont les trois situations où le décalage se perd. Corriger prend cinq secondes quand le bloc est frais, dix minutes quand il fait vingt lignes.


Questions fréquentes

Question

Pourquoi Python impose-t-il l'indentation ?

Parce qu'elle porte la structure au lieu de la décorer. Dans les langages à accolades, un code mal aligné reste valable et peut mentir sur ce qu'il fait : ce que l'oeil regroupe n'est pas ce que la machine exécute. En Python, ce qui se voit est ce qui s'exécute.

Question

Peut-on rattraper cette erreur avec un try ?

Non, et c'est ce qui la sépare d'une exception ordinaire. Elle est levée pendant l'analyse du fichier, donc avant que le bloc de rattrapage existe aux yeux de Python. Le fichier doit être corrigé, il n'y a aucun contournement possible.

Question

Mon éditeur n'affiche aucune erreur, pourquoi Python en signale-t-il une ?

Parce que l'éditeur dessine une tabulation et une suite d'espaces à la même largeur, ce que Python ne fait pas : vous voyez deux lignes alignées, il lit deux niveaux. Activez l'affichage des caractères invisibles, ou changez la largeur de tabulation de l'éditeur.

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.