Opérations Logiques

Booléens

On va s’attaquer pour cette leçon à un nouveau type de données. Il permet d’effectuer des opérations logiques. Il s’agit des booléens (bool en python).

Il n’y en en fait que deux exemplaires, VRAI et FAUX ou en python:

>>> True
True
>>> False
False
>>> type(True)
<class 'bool'>

Noter qu’il n’y a qu’une seule façon valide de les écrire!

>>> false
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'false' is not defined
>>> TRUE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'TRUE' is not defined

Opérateurs logiques

On peut combiner plusieurs booléens de trois manières distinctes.

  1. La négation via not

    >>> not True
    False
    >>> not False
    True
  2. La conjonction via and

    >>> False and False
    False
    >>> False and True
    False
    >>> True and False
    False
    >>> True and True
    True

    Elle renvoie True lorsque toutes les opérandes sont True.

  3. La disjonction via or

    >>> False or False
    False
    >>> False or True
    True
    >>> True or False
    True
    >>> True or True
    True

    Elle renvoie True lorsqu’au moins une des opérandes est True.

Notez que les deux derniers opérateurs se généralisent à des conteneurs de booléens via les fonction any et all.

>>> vrais = (True, True, True)
>>> any(vrais)
True
>>> all(vrais)
True
>>> faux = (False, False, False)
>>> any(faux)
False
>>> all(faux)
False
>>> mixte = (False, True, False)
>>> all(mixte)
False
>>> any(mixte)
True

Opérateurs de comparaisons

L’intérêt des booléens est de permettre de raisonner suivant que certains propriétés sont vraies ou fausses. On produit des booléens via des opérateurs de comparaisons.

  1. Le test d’égalité via == permet de savoir si deux objets ont même valeurs.(ATTENTION = est réservé à l’affectation!)

    >>> x = 123456789
    >>> y = 123456789
    >>> z = 987654321
    >>> x == y
    True
    >>> x == z
    False

    REMARQUE deux séquences (tuple pour l’instant mais list d’ici peu) sont égales si toutes leurs valeurs le sont (et à la même position)

    >>> (1, 2) == (1, 2)
    True
    >>> (1, 2) == (2, 1)
    False
    >>> (1, 2, 3) == (1, 2)
    False
  2. Pour tester au contraire la différence de valeurs, on peut utiliser la négation not ou l’opérateur !=

    >>> x = 123456789
    >>> y = 123456789
    >>> z = 987654321
    >>> not (x == y)
    False
    >>> x != y
    False
    >>> not (x == z)
    True
    >>> x != z
    True
  3. Comme on l’a déjà vu plusieurs fois, en python on fait la différence entre l’égalité (qui concerne la valeur de l’objet) et l’identité (qui concerne l’objet lui même). Pour tester l’identité on utilise is

    >>> x = 123456789
    >>> y = x
    >>> z = 123456789
    >>> x == y
    True
    >>> x == z
    True
    >>> x is y
    True
    >>> x is z
    False

    REMARQUE lorsque on veut nier l’identité on peut utiliser is not qui se lit plus naturellement que l’utilisation de la négation en tête:

    >>> x = 123456789
    >>> y = x
    >>> z = 123456789
    >>> not (x is y)
    False
    >>> not (x is z)
    True
    >>> x is not y
    False
    >>> x is not y
    False
  4. On peut comparer la grandeur des nombres via les opérateurs strictement plus petit et strictement plus grand:

    >>> 1 < 2
    True
    >>> 2 < 1
    False
    >>> 1 > 2
    False
    >>> 2 > 1
    True

    Les opérateurs de comparaison relatifs sont <= et >= (le signe = vient en deuxième car on dit ou égal en second)

    >>> 1 < 1
    False
    >>> 1 <= 1
    True
    >>> 1 >= 1
    True

    REMARQUE pour les séquences on utilise l’ordre dit lexicographique, c’est à dire qu’on fait les comparaisons des valeurs de gauche à droite. Plus succinctement les séquences sont ordonnées comme leur première composante non égale!

    >>> (1, 2) < (3, 0)
    True
    >>> (1, 2) > (1, 1)
    True

ATTENTION les str sont elles aussi comparables via l’ordre lexicographique (et pas par leurs longueurs), mais cela permet juste de ramener la comparaison caractère par caractère. En première approche on peut utiliser l’ordre alphabétique pour analyser la situation.

>>> "a" < "b"
True
>>> "d" < "z"
True
>>> "f" < "b"
False

En fait la situation est plus délicate, ce qui est réellement comparé est l’unicode correspondant aux caractères (qu’on avait vu via l’échappement \uXXXX), cela rend certaines comparaisons peu intuitives (on utilisera donc avec modération!)

>>> "." < "a"
True
>>> "A" < "a"
True

Notez qu’on peut comprendre un peu mieux ce qui se passe en utilise la fonction ord pour récupérer l’unicode correspondant:

>>> ord(".")
46
>>> ord("a")
97
>>> ord("A")
65

Exercices

  1. Comparer les expressions booléennes not (x and y) et (not x) or (not y) pour toutes les valeurs possibles (booléennes) de x, y et z.
  2. Comparer les expressions booléennes x and (y or z) et (x and y) or (x and z) pour toutes les valeurs possibles (booléennes) de x, y et z.
  3. Coder un exemple permettant de décider, lorsqu’on évalue E1 or E2 (où E1 et E2 sont des expressions booléennes) entre les deux scénarios suivants:

Pour aller plus loin

On pourra essayer

>>> help("BOOLEAN")

et

>>> help("COMPARISON")

Corrections

  1. On utilise le code

    >>> x, y = True, True
    >>> (not (x and y)) == ((not x) or (not y))
    True
    >>> x, y = True, False
    >>> (not (x and y)) == ((not x) or (not y))
    True
    >>> x, y = False, True
    >>> (not (x and y)) == ((not x) or (not y))
    True
    >>> x, y = False, False
    >>> (not (x and y)) == ((not x) or (not y))
    True

    On voit que les deux expressions évaluent toujours identiquement, on a le même résultat en échangeant or et and.

  2. On code de manière laborieuse (là encore on appréciera les boucles!)

    >>> x, y, z = True, True, True
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = True, True, False
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = True, False, True
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = True, False, False
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = False, True, True
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = False, True, False
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = False, False, True
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True
    >>> x, y, z = False, False, False
    >>> (x and (y or z)) == ((x and y) or (x and z))
    True

    On peut constater que les deux expressions booléennes sont égales indépendamment des valeurs des variables booléennes. On dit qu’on a distributivité, notez que si l’on substitue and et or le résultat est encore vrai. On pourra aller regarder ici pour plus d’informations sur les deux premières questions.

  3. Ici on va choisir pour E2 une expression dont l’évaluation fait planter python.

    >>> (12 / 0) != 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: division by zero
    >>> (1 == 1) or (12 / 0 != 5)
    True

    On constate que c’est le deuxième scénario qui a lieu, on dit qu’on a une évaluation fainéante. Le même phénomène a lieu pour E1 and E2 si E1 évalue à False. On signale ce phénomène car il est utilisée de manière passablement astucieuses dans différentes situations. (et malheureusement assez impénétrable pour qui ne connait pas le phénomène)