assert en Python : vérifier une hypothèse pendant le développement

assert vérifie une hypothèse pendant le développement et lève une AssertionError si elle est fausse. Ce n'est jamais un contrôle de saisie.
5 min de lecture
Believemy logo

Définition

En écrivant du code, on tient sans cesse des choses pour acquises : cette liste n'est jamais vide ici, ce compteur ne descend pas sous zéro. Rien de cela n'est écrit noir sur blanc, et c'est ce qui coûte cher. Le jour où l'une de ces suppositions devient fausse, le programme ne s'arrête pas là où elle a été trahie : il casse trois fonctions plus loin, sur un message qui ne désigne plus le coupable.

assert répond à cet ennui. Cette instruction vérifie qu'une condition est vraie à un point précis du programme. Si elle l'est, rien ne se passe. Sinon, Python lève une AssertionError et tout s'arrête, à l'endroit exact où la supposition a cessé d'être vraie.

Voici la forme la plus courante : une hypothèse posée en tête de fonction.

PYTHON
def moyenne(notes):
    # Une moyenne n'a aucun sens sur une liste vide.
    assert len(notes) > 0, "la liste de notes est vide"
    return sum(notes) / len(notes)

moyenne([])
# AssertionError: la liste de notes est vide

Deux parties composent la forme complète : la condition à vérifier, puis un message facultatif placé après une virgule. Ce message a des airs d'ornement, il n'en est pas un : sans lui, le traceback affiche la ligne fautive et rien de plus, à charge pour le lecteur de deviner ce qui était attendu.


Ce n'est pas un contrôle de saisie

Le malentendu le plus coûteux consiste à valider des données extérieures avec une assertion. La tentation se comprend : assert age >= 18 tient sur une ligne, là où la version correcte en demande trois.

L'interdit tient au sort réservé à ce mot-clé en mode optimisé, quand l'interpréteur est lancé avec l'option -O. Les lignes concernées ne sont pas ignorées à l'exécution : elles sont retirées à la compilation, comme si personne ne les avait jamais écrites.

Attention

Un contrôle de droits écrit sous forme d'assertion laisse passer en production exactement ce qu'il était censé bloquer. Aucune erreur, aucune trace dans les logs : le code paraît protégé, il ne l'est plus.

Une seule question tranche : d'où vient la donnée vérifiée ? Le tableau met chaque situation courante en face de l'écriture qui convient.

SituationÉcriture juste
Une saisie utilisateur douteuseUn if puis un raise de ValueError
Un appel réseau qui peut échouerUn bloc try autour de l'appel
Un droit d'accès à contrôlerUne exception explicite, jamais une assertion
Une hypothèse interne au codeUne assertion, à sa juste place

Si la condition peut devenir fausse à cause du monde extérieur, ce n'est donc pas une assertion. Une donnée venue d'un formulaire, d'un fichier ou d'une API en fait partie, quelle que soit la confiance placée dans sa source.


Le piège des parenthèses

Ce mot-clé n'est pas une fonction, et les parenthèses ne l'entourent donc pas. L'habitude prise avec print() pousse pourtant à en ajouter, et Python accepte la ligne sans broncher.

Écrire assert (condition, "message") revient à lui passer un argument unique : un tuple de deux éléments. Or un tuple non vide compte toujours comme vrai. L'assertion réussit alors systématiquement, quelle que soit la condition réelle.

PYTHON
# Silencieux : le tuple est toujours vrai,
# la condition n'est jamais évaluée.
assert (total > 0, "total négatif")

# Correct : aucune parenthèse autour de l'ensemble.
assert total > 0, "total négatif"

Les versions récentes de Python signalent cette écriture par un avertissement, encore faut-il le lire. C'est le genre de faute qui laisse croire qu'une batterie de vérifications tourne, alors qu'aucune d'entre elles ne mord.


Où il est à sa place

Les tests automatisés sont son terrain naturel. Une fonction de test se résume souvent à trois gestes : préparer des données, appeler le code, poser une assertion sur le résultat. Les bibliothèques de test les plus répandues en Python reposent entièrement sur ce mot-clé.

Bon à savoir

pytest réécrit les assertions au chargement des fichiers de test. C'est ce qui explique qu'un échec affiche les deux valeurs comparées au lieu d'une AssertionError nue.

Hors des tests, le deuxième usage est l'invariant interne, cette hypothèse qu'un développeur pose sans jamais l'écrire : cette liste est déjà triée, ce compteur reste positif. Une assertion la transforme en vérification pour le prix d'une ligne, lisible par qui reprendra le code dans six mois.

Le troisième usage est la documentation qui s'exécute. Une assertion en tête de fonction annonce ce qu'elle attend, comme une docstring, à une différence près : une docstring peut s'éloigner du code sans que personne s'en aperçoive, l'assertion proteste dès qu'on la contredit.


Questions fréquentes

Question

Faut-il rattraper une AssertionError ?

Presque jamais, et la raison tient à ce qu'elle signale. Une assertion qui échoue ne décrit pas une situation prévue : elle annonce un défaut dans le code lui-même. La rattraper revient à masquer un bug au lieu de le corriger. Si le cas était prévisible, c'est une exception adaptée qu'il fallait lever.

Question

Comment désactiver les assertions en production ?

En lançant l'interpréteur avec l'option -O, qui retire toutes les assertions du code compilé et met la variable __debug__ à faux. Le gain de vitesse reste minuscule, mais l'existence même de cette option fixe la règle : leur disparition ne doit rien changer au comportement du programme.

Question

Quelle différence avec un test conditionnel suivi d'une levée d'exception ?

L'intention, avant tout. Un if suivi d'un raise traite un cas que le programme prévoit et sait gérer : une saisie vide, un fichier absent. Une assertion déclare une hypothèse qui ne doit jamais être fausse. Le premier reste actif en production, la seconde s'adresse au développement et peut disparaître sans conséquence.

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.