Définition
Le script tournait très bien jusqu'à cette ligne, et voilà que Python s'arrête net en évoquant un nom qu'il ne reconnaît pas. C'est exactement ce que signale NameError : au moment d'exécuter cette ligne précise, l'interpréteur cherche une variable, une fonction ou un module portant ce nom, et ne trouve rien nulle part dans le programme.
La différence avec une SyntaxError se sent tout de suite à l'usage. Une erreur de syntaxe empêche même le fichier de démarrer, parce que sa forme est invalide avant toute exécution. Une NameError, elle, laisse le programme tourner normalement, parfois longtemps, avant de buter sur la ligne fautive : le code est parfaitement lisible, seul ce nom précis n'existe pas.
Voici la forme la plus courante du problème, une simple variable mal recopiée :
print(totl)
# NameError: name 'totl' is not defined. Did you mean: 'total'?Depuis la version 3.10, Python ajoute souvent cette suggestion entre parenthèses. Il compare le nom fautif à ceux qui existent déjà dans le programme et propose le plus proche, ce qui règle la moitié des cas sans même avoir besoin de relire tout le fichier.
Les quatre causes
Ce message unique recouvre en réalité quatre situations bien différentes, et savoir laquelle est en cause fait gagner un temps précieux. Le tableau suivant résume comment reconnaître chacune d'un coup d'œil, avant de s'attarder sur la plus piégeuse.
| Cause | Signe distinctif |
|---|---|
| Faute de frappe | Le nom suggéré ressemble au vôtre |
| Module non importé | Le nom est celui d'une bibliothèque |
| Variable définie dans une autre fonction | Le nom existe ailleurs dans le fichier |
| Variable créée dans une branche non prise | Le programme marche parfois |
Les deux premières causes se corrigent en quelques secondes une fois repérées : on corrige l'orthographe, ou on ajoute l'import manquant en tête de fichier. La troisième demande simplement de se souvenir qu'une fonction ne voit jamais les variables d'une autre fonction, même voisine : chacune vit dans son propre espace.
La quatrième cause mérite qu'on s'y attarde, parce qu'elle ne se manifeste pas à chaque exécution. Une variable affectée uniquement à l'intérieur d'un if n'existe que si la condition a été vraie ce jour-là. Le programme peut donc fonctionner sans accroc des dizaines de fois de suite, puis s'arrêter net le jour où les données empruntent l'autre chemin.
if solde > 0:
message = "Crédit disponible"
print(message) # NameError si le solde est nulCe genre de NameError passe souvent les tests sans encombre, parce que les jeux de données de test tombent rarement sur le cas limite. Il refait surface en production, sur la première donnée réelle qui emprunte la branche restée invisible jusque là.
Le remède consiste à donner une valeur par défaut à la variable avant la condition, ou à fermer la structure par un else qui couvre systématiquement tous les cas restants.
Sa cousine, UnboundLocalError
Une variante existe, encore plus déroutante, parce qu'elle touche une variable qui semble déjà exister sous vos yeux. Lorsqu'une fonction affecte une variable n'importe où dans son corps, Python décide que cette variable est locale à la fonction entière, y compris sur les lignes qui précèdent l'affectation elle même. La lire avant cette ligne déclenche alors une UnboundLocalError, même si une variable du même nom existe bel et bien au niveau du module.
compteur = 0
def incrementer():
print(compteur) # UnboundLocalError, et non 0
compteur = compteur + 1Rien, à la lecture de print(compteur), ne laisse deviner le problème : la variable globale vaut bien 0. C'est la ligne suivante, celle qui affecte compteur, qui transforme rétroactivement tout le corps de la fonction en zone locale, du début jusqu'à la fin.
Pour lire et modifier une variable globale depuis l'intérieur d'une fonction, il faut la déclarer avec global avant de s'en servir. Sans cette déclaration, toute affectation dans le corps de la fonction crée une variable locale distincte, même si elle porte le même nom qu'une variable du module.
Le diagnostic en trois secondes
Le message donne toujours le nom fautif entre guillemets, ce qui simplifie beaucoup la suite. Trois vérifications rapides suffisent, dans cet ordre : le nom est-il bien orthographié partout où il apparaît, l'import correspondant se trouve-t-il en tête de fichier, et la variable est-elle définie sur tous les chemins qui mènent jusqu'à cette ligne.
Si les trois vérifications ne donnent rien, il reste le cas de la portée : la variable existe bien quelque part, mais dans une autre fonction que celle qui la cherche. Deux fonctions ne partagent rien, et il faut alors passer la valeur en argument puis la renvoyer avec return.
Questions fréquentes
Quelle différence avec AttributeError ?
NameError porte sur un nom que Python ne trouve nulle part dans le programme, alors qu'une AttributeError porte sur un objet bien connu auquel on demande quelque chose qu'il ne possède pas. Le premier message parle d'un nom introuvable, le second d'un objet précis et d'un attribut qui lui manque.
Pourquoi ma variable de boucle n'existe-t-elle plus après coup ?
Si la séquence parcourue était vide, la boucle n'a fait aucun tour, et la variable qui aurait dû naître à l'intérieur n'a donc jamais été créée. Sur une séquence non vide en revanche, elle survit tranquillement à la boucle et conserve la dernière valeur qu'elle a prise.
Comment repérer ces erreurs avant même l'exécution ?
Un éditeur correctement configuré pour Python souligne les noms inconnus au fur et à mesure de la frappe, et les outils d'analyse statique les signalent sur l'ensemble d'un projet en quelques secondes. C'est le genre de faute qu'aucune équipe ne devrait découvrir en production.