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

ValueError apparaît quand une fonction reçoit le bon type de donnée, mais une valeur qu'elle ne sait pas exploiter. D'où elle vient, comment la corriger.
5 min de lecture
Believemy logo

Définition

Une fonction Python attend souvent plus qu'un type : elle attend une valeur qui a du sens. Donnez-lui une chaîne là où elle en réclame une, elle ne se plaindra pas, le type est bon. Mais si le contenu ne correspond à rien qu'elle sache traiter, elle doit le signaler autrement : c'est le rôle de cette exception, ValueError.

PYTHON
age = int("douze")  # on voulait un nombre, on tape un mot

# ValueError: invalid literal for int() with base 10: 'douze'

La chaîne "douze" est bien une chaîne, et int accepte parfaitement les chaînes en argument. Le problème n'est pas là : ce texte précis ne contient simplement pas de nombre reconnaissable. Cette nuance change l'endroit où chercher quand quelque chose casse. Passer une liste à la même fonction aurait produit une TypeError à la place, puisque le reproche aurait alors porté sur la nature de l'argument, et non sur son contenu.


La différence avec TypeError

Confondre les deux erreurs fait chercher au mauvais endroit pendant de longues minutes, parce qu'on corrige le type d'une donnée qui était déjà du bon type. Trois appels suffisent à voir où passe la frontière entre les deux.

AppelRésultatRaison
int("12")Aucune erreurUne chaîne qui contient bien un nombre
int("douze")ValueErrorLe bon type, un contenu inconvertible
int([1, 2])TypeErrorUn type que la fonction ne sait pas traiter

La distinction devient presque un réflexe une fois ces trois cas en tête : si corriger le contenu de la valeur suffit à faire passer l'appel, c'est une ValueError ; s'il faut changer sa nature, c'est une TypeError. Le traceback affiche toujours la valeur fautive sur sa dernière ligne, inutile de la deviner.


Où elle apparaît le plus souvent

La conversion d'une saisie arrive largement en tête, pour une raison simple : un input renvoie toujours du texte, quoi que la personne ait tapé. Convertir ce texte avec int ou float revient à faire dépendre tout le programme de ce qui se trouve réellement au clavier à cet instant.

Le dépaquetage vient ensuite, pour une raison voisine. Une affectation multiple exige un nombre d'éléments exact de part et d'autre du signe égal, et un split sur une ligne mal formée n'en fournit pas toujours autant.

PYTHON
nom, prenom = "Dupont".split(";")  # la ligne attendue contenait un point-virgule

# ValueError: not enough values to unpack (expected 2, got 1)

Suivent les recherches qui échouent, comme liste.index(valeur) ou liste.remove(valeur) appelées sur un élément absent, puis les fonctions mathématiques sollicitées hors de leur domaine, comme une racine carrée sur un nombre négatif. Ces situations partagent la même origine : la donnée vient de l'extérieur du programme, et personne ne l'a vérifiée avant de s'en servir.


La rattraper, ou la lever soi-même

Le rattrapage se fait avec try et except, en visant l'erreur précise plutôt qu'une classe trop générale.

PYTHON
while True:
    saisie = input("Votre age : ")
    try:
        age = int(saisie)
        break
    except ValueError:
        print("Chiffres uniquement, merci.")
Attention

Écrire except Exception à la place de except ValueError semble plus prudent, mais ça avale aussi les fautes de frappe dans un nom de variable ou une clé absente. Le programme continue de tourner en silence, et le vrai bug se découvre bien plus tard, ailleurs.

L'autre moitié du travail consiste à lever la ValueError soi-même, dans ses propres fonctions, avec raise. Une fonction qui reçoit une durée négative ou un mois valant 13 a tout intérêt à refuser immédiatement, avec un message qui nomme la valeur reçue, plutôt qu'à laisser une donnée absurde se propager sur dix appels.

PYTHON
def appliquer_remise(prix, pourcentage):
    if not 0 <= pourcentage <= 100:
        raise ValueError(f"pourcentage hors bornes : {pourcentage}")
    return prix * (1 - pourcentage / 100)


La vraie correction est en amont

Une ValueError rattrapée en silence n'a rien corrigé du tout, elle a seulement caché le symptôme. Elle signale presque toujours qu'une donnée est entrée dans le programme sans avoir été contrôlée, et l'endroit où elle éclate est rarement celui où le problème est né.

La méthode qui fait gagner le plus de temps consiste à valider à la frontière, au moment où le texte est saisi, où le fichier est lu, où la réponse d'un service extérieur est décodée. Passé ce point, le reste du programme travaille sur des données dont la forme est garantie, et l'erreur disparaît des couches profondes du code, là où elle coûte le plus cher à comprendre.


Questions fréquentes

Question

Comment convertir une saisie sans risquer l'erreur ?

Il n'existe pas de conversion tolérante en Python : int réussit ou lève. La seule approche fiable consiste à entourer l'appel d'un try, ou à valider la chaîne au préalable avec une méthode comme isdigit, qui ne gère toutefois ni le signe négatif ni les décimales.

Question

Pourquoi mon dépaquetage échoue-t-il sur une seule ligne du fichier ?

Parce que cette ligne précise n'a pas le format attendu : un séparateur manquant, un champ vide en fin de ligne, ou une ligne blanche finale. Fixer un nombre maximal de coupes avec split(";", 1), ou tester la longueur du résultat avant d'affecter, règle le problème pour de bon.

Question

Faut-il lever cette erreur ou créer sa propre exception ?

Tant que le problème se résume à une valeur refusée, l'erreur standard reste le meilleur choix : tout le monde la connaît et sait la rattraper. Une exception maison ne se justifie que si l'appelant doit distinguer ce cas précis des autres pour réagir différemment, ce qui est plus rare qu'il n'y paraît.

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.