Définition
Un programme passe son temps à trancher. Cet utilisateur est-il majeur, ce panier est-il vide, ce fichier existe-t-il ? Ces questions n'admettent que deux réponses, et il fallait un type pour les représenter, comme il en existe un pour les nombres et un pour le texte. Ce type s'appelle bool, du nom du mathématicien George Boole.
Il ne compte que deux valeurs possibles, True et False, toutes deux écrites avec une majuscule initiale : true en minuscules n'existe pas en Python et déclenche une erreur de nom. C'est le type que renvoie toute comparaison, et celui que Python évalue derrière un if, derrière un while ou derrière un filtre.
age = 20
majeur = age >= 18 # la comparaison produit une valeur, on peut la ranger
print(majeur) # True
print(type(majeur)) # <class 'bool'>Cet exemple montre qu'une comparaison n'appartient pas au if : elle fabrique une valeur ordinaire, que vous pouvez ranger dans une variable ou passer à une fonction.
Le nom bool désigne aussi une fonction de conversion : bool(valeur) répond vrai ou faux pour n'importe quel objet. Python l'appelle en coulisses chaque fois qu'une condition est évaluée, et cela change la manière d'écrire du code, puisqu'une liste vide suffit alors à faire un test.
Ce que Python considère comme faux
Puisque n'importe quel objet peut se retrouver dans une condition, il a fallu une règle pour les valeurs qui ne sont ni vraies ni fausses par nature, comme une liste ou une chaîne. Elle tient en une idée : ce qui est vide ou nul est faux, tout le reste est vrai. Le tableau ci-dessous donne la liste complète, puis les cas que l'on croit faux à tort.
| Valeur | Ce que renvoie bool() |
|---|---|
0 et 0.0 | False |
"", la chaîne vide | False |
[], {}, () | False |
None | False |
-1, 0.1, "0" | True |
| Un objet quelconque | True par défaut |
L'avant-dernière ligne est celle qui surprend le plus. Un nombre négatif est vrai parce que la règle ne parle pas de signe mais de zéro : un solde négatif passe un if solde: aussi bien qu'un solde positif.
La chaîne "0" est vraie parce que ce qui compte, pour une chaîne, est sa longueur et jamais ce qu'elle raconte. De là vient un bug très fréquent sur les valeurs saisies au clavier, car la fonction input renvoie toujours du texte : if reponse: reste vrai même lorsque la personne a tapé zéro.
Les opérateurs and et or ne renvoient pas un booléen, mais l'un de leurs deux opérandes : "" or "anonyme" vaut la chaîne "anonyme", et non True. C'est ce qui rend possible l'écriture nom = saisie or "anonyme".
Convertir sans se tromper
Le besoin revient dans tous les programmes : une valeur arrive de l'extérieur, d'un formulaire ou d'un fichier de configuration, et il faut en tirer un oui ou un non. Le réflexe est d'appeler bool() dessus, puisque c'est la fonction de conversion. C'est précisément ce qu'il ne faut pas faire.
Tout tient dans une ligne : bool("False") vaut True. La chaîne de cinq lettres n'a aucun rapport avec le booléen du même nom : pour bool(), c'est une chaîne non vide comme une autre, donc vraie.
reponse = "False"
print(bool(reponse)) # True : la chaîne n'est pas vide
print(reponse == "False") # True : comparaison écrite à la main
print(reponse.lower() == "true") # False : la forme habituelleLa troisième ligne montre la manière de faire recommandée : on abaisse la casse, puis on compare au texte attendu, de sorte que "True", "true" et "TRUE" soient traités pareil. Rien n'empêche d'accepter aussi "1" ou "oui" : cette décision appartient au programme, pas au langage.
Un fichier de configuration relu avec bool() allume tout ce qu'il est censé éteindre : la ligne debug = False devient True, et le mode debug reste actif en production sans le moindre message d'erreur.
Un booléen est aussi un entier
Voici une propriété qui ressemble à un détail interne et qui rend service tous les jours : le type bool hérite de int. Un booléen est un entier, True valant 1 et False valant 0 dans le moindre calcul.
La conséquence est immédiate : compter les cas vrais d'une série revient à les additionner, sans compteur à incrémenter ni boucle à écrire.
notes = [12, 8, 15, 4, 18]
reussites = sum(note >= 10 for note in notes) # cinq booléens additionnés
print(reussites) # 3La deuxième ligne produit un booléen par note, que sum additionne comme des 1 et des 0. Cette parenté explique aussi deux bizarreries : True + True donne 2, et isinstance(True, int) répond vrai. Le jour où une fonction doit refuser True là où elle attend une quantité, la vérification passe donc par type(valeur) is bool.
Questions fréquentes
Faut-il écrire if actif == True ?
Non. Si la variable contient déjà un booléen, if actif: dit la même chose en moins de signes, et la forme négative s'écrit avec not. La comparaison explicite devient même fausse dès que la valeur n'est pas un booléen : une liste non vide est vraie dans un if, alors que la comparer à True renvoie False.
Pourquoi une liste vide se comporte-t-elle comme False ?
Parce que les collections répondent sur leur contenu : une longueur nulle vaut faux, une longueur positive vaut vrai. C'est l'information que donne len, et cela permet d'écrire if resultats: plutôt que if len(resultats) > 0:, qui oblige à traduire mentalement.
Comment vérifier que tous les éléments d'une liste sont vrais ?
Avec all, qui renvoie True tant qu'aucun élément n'est faux, et avec any, qui répond dès qu'un seul l'est. Les deux acceptent une expression génératrice, ce qui évite de construire une liste intermédiaire uniquement pour la tester. Ces réflexes se travaillent sur des cas réels dans la formation Python.