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

AttributeError signale qu'un objet ne possède pas le nom demandé après le point. Neuf fois sur dix, la méthode est bonne et c'est l'objet qui surprend.
5 min de lecture
Believemy logo

Définition

Une ligne parfaitement raisonnable, un script lancé, et Python s'arrête net : la méthode utilisée tous les jours n'existerait pas. La scène déroute tant qu'on lit le point comme un séparateur. C'est en réalité une demande adressée à l'objet : fournir ce qu'il range sous ce nom.

AttributeError est la réponse de Python quand la demande échoue. L'interpréteur cherche le nom écrit après le point, ne le trouve ni sur l'objet ni sur sa classe, et s'arrête plutôt que d'inventer une valeur. Son message nomme toujours le type réel de l'objet, puis le nom réclamé.

PYTHON
message = "believemy"

# append existe bien en Python, mais sur les listes, pas sur les chaînes
message.append("!")

# AttributeError: 'str' object has no attribute 'append'

Python ne dit pas que le nom est mal orthographié, il dit qu'il n'existe pas sur ce type. La nuance déplace l'enquête : la question n'est plus comment s'écrit la méthode, mais ce que contient la variable.

Elle sépare aussi deux erreurs voisines. Une faute de frappe sur une variable seule donne une NameError, aucun nom de ce genre n'existant dans la portée. La même faute après un point donne bien une AttributeError : le nom existe peut-être ailleurs, mais pas ici.


Lire le message dans le bon sens

Le premier réflexe consiste à chercher le bon nom de méthode. C'est presque toujours le mauvais : neuf fois sur dix la méthode est correcte, et c'est l'objet qui n'est pas celui qu'on croyait tenir.

Le message se coupe en deux moitiés, chacune posant une question différente. Voici laquelle poser en premier.

Ce que dit le messageLa question qu'il faut poser
'str' objectPourquoi cet objet est-il de ce type ?
has no attribute 'append'Ce nom existe-t-il sur ce type ?
La ligne du tracebackOù l'objet a-t-il été fabriqué ?

Commencez par la première ligne. Une liste arrivée sous forme de chaîne, un dictionnaire là où un objet était prévu, un nombre au lieu d'un texte : aucun de ces cas ne se règle en changeant la méthode.

Reste à savoir où l'objet a pris ce type, et sur ce point le traceback égare : il désigne la ligne qui a échoué, pas celle qui a fabriqué l'objet. Remontez jusqu'à l'endroit où la variable reçoit sa valeur.


Le cas NoneType, de loin le plus fréquent

Une variante revient si souvent qu'elle mérite un traitement à part : 'NoneType' object has no attribute. Elle ne signale pas un type exotique mais une absence : la variable vaut None, donc une opération en amont n'a rien renvoyé.

PYTHON
ligne = "prenom;nom;age"

# split renvoie bien une liste, mais sort la trie sur place et ne renvoie rien
champs = ligne.split(";").sort()

champs.index("nom")

# AttributeError: 'NoneType' object has no attribute 'index'

champs ne récupère pas la liste triée mais l'absence de valeur, et c'est la ligne suivante qui échoue. L'erreur apparaît un cran après sa cause, d'où le temps perdu à relire la mauvaise instruction.

Bon à savoir

Ce silence est délibéré : une méthode qui modifie un objet sur place renvoie None pour éviter de laisser croire à une copie. Enchaîner un appel derrière elle est donc toujours une erreur.

Presque toujours, la cause se trouve à l'un de ces trois endroits. Le plus courant est celui de l'exemple : une méthode qui modifie sur place, comme sort, append ou update, avec un appel accroché derrière.

Vient ensuite la fonction maison dont un chemin oublie le return : le return est écrit dans une condition, et l'appelant reçoit une absence de valeur sans en être averti. Vient enfin la recherche infructueuse, beaucoup de fonctions signalant l'échec par None.


Corriger plutôt que masquer

Sur un objet que vous écrivez, le type est bon mais l'attribut n'a jamais été créé : soit il est défini ailleurs que dans __init__, dans une méthode pas encore appelée, soit un singulier a été confondu avec son pluriel. Ici, le message nomme la classe, donc le fichier à ouvrir.

PYTHON
class Panier:
    def __init__(self):
        self.articles = []  # l'attribut porte un pluriel

panier = Panier()
panier.article

# AttributeError: 'Panier' object has no attribute 'article'

Quand l'attribut est réellement optionnel, deux fonctions intégrées évitent le plantage sans rien dissimuler. hasattr(objet, "nom") répond par vrai ou faux et sert à brancher le code. getattr(objet, "nom", defaut) renvoie une valeur de repli, ce qui épargne la condition. Un bloc try convient aussi, à condition de traiter le cas à l'intérieur.

Attention

Un except AttributeError suivi d'un pass ne corrige rien : le programme continue avec une donnée manquante, et l'erreur ressort plus loin sous une forme méconnaissable.


Questions fréquentes

Question

Quelle différence avec une TypeError ?

Une TypeError signale une opération impossible entre types incompatibles, comme une addition entre un texte et un nombre. AttributeError ne porte que sur le nom cherché après le point. Les deux remontent souvent à la même cause : un objet qui n'est pas du type attendu.

Question

Faut-il préférer hasattr ou un bloc try ?

hasattr se lit mieux quand la présence de l'attribut est une vraie question métier, un réglage facultatif par exemple. Le bloc try devient préférable dès que l'accès fait partie du chemin normal, car il évite de chercher l'attribut deux fois.

Question

Pourquoi l'erreur mentionne-t-elle un module ?

Parce qu'un module est un objet comme un autre. Le message module has no attribute apparaît après un import réussi mais mal ciblé, ou quand un fichier personnel porte le nom d'une bibliothèque connue et prend sa place. Sinon, c'est une ModuleNotFoundError.

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.