Outils Conditions

Identification

Infoforall

13 - Conditions


Nous abordons aujourd'hui une autre notion très importante pour réaliser des choses intéressantes : les instructions conditionnelles.

En une question : comment réaliser des choses différentes en fonction de la situation ?

Evaluation : 5 questions

  questions 06-11

  question -

DM 🏠 : Non

Documents de cours PDF : .PDF

Sources latex : .TEX et entete.tex et licence.tex

1 - Booléens

(RAPPELS) 1.1 Booléen : vrai ou faux

Booléens

Lorsqu'on utilise certains opérateurs booléens, l'interpréteur évalue votre expression en répondant :

  • True si c'est vrai ou
  • False sinon.

Pas de réponse de type "peut être". Néanmoins, la demande peut provoquer une erreur.

Opérateurs renvoyant une valeur booléenne

  • relation strictement supérieur avec >
  • int|float > int|float -> bool

    Le signe | veut dire OU. On peut donc placer un entier ou un flottant.

    >>> 40 > 30 True

    On pose la question suivante à l'interpréteur Python : "40 est-il strictement supérieur à 30 ?".

    str > str -> bool

    >>> "crocodile" > "tortue" False

    On pose la question suivante à l'interpréteur Python : "Le mot "crocodile" est-il derrière le mot "tortue" dans le dictionnaire ?".

    On voit qu'on utilise ici l'ordre lexicographique, l'ordre du dictionnaire (si tout est en minuscule).

    Dans une autre activité, nous détaillerons un peu plus comment cela fonctionne, notamment la gestion des majuscules ou des autres caractères.


  • opérateur d'égalité avec ==
  • Puisque = est déjà utilisé pour l'affectation des variables (a = 50 par exemple), les concepteurs de Python ont choisi la syntaxe d'un double signe égal pour le test d'égalité.

    >>> 40 == 3 * 10 False

    On pose la question suivante à l'interpréteur Python : "40 est-il identique à 3 * 10 ?".

    >>> 40 == 4 * 10 True

    On pose la question suivante à l'interpréteur Python : "40 est-il identique à 4 * 10 ?".

    >>> 0.3 == 3 * 0.1 False

    On pose la question suivante à l'interpréteur Python : "0.3 est-il identique à 3 * 0.1 ?". Pourquoi obtient-on False ? Simplement car 0.1 n'a pas été mémorisé de façon exacte, et donc 3 * presque 0.1, ca ne donne pas presque 0.3 !


  • opérateur de différence avec !=
  • Puisque n'est pas facilement accessible sur un clavier, les concepteurs de Python ont choisi la syntaxe != pour le test de différence. Dans d'autres langages, c'est parfois <>.

    >>> 40 != 3 * 10 True

    On pose la question suivante à l'interpréteur Python : "40 est-il différent de 3 * 10 ?".

    >>> 40 != 4 * 10 False

    On pose la question suivante à l'interpréteur Python : "40 est-il différent de 4 * 10 ?".


  • autres opérateurs de comparaison :
  • >>> 40 < 30 False

    On pose la question suivante à l'interpréteur Python : "40 est-il strictement inférieur à 30 ?".

    >>> 40 <= 30 False

    On pose la question suivante à l'interpréteur Python : "40 est-il inférieur ou égal à 30 ?".

    >>> 40 >= 30 False

    On pose la question suivante à l'interpréteur Python : "40 est-il supérieur ou égal à 30 ?".


  • appartenance avec in
  • Le mot-clé in permet de savoir si un élément a est présent dans un élément b : a in b

    Si la réponse est True, c'est que a apparaît dans b. Sinon, la réponse sera False.

    Voici un moyen de tester facilement si quelqu'un d'allergique au soja peut manger un produit dont on connaît la composition :

    >>> "soja" in "Sucre ; huile de colza ; eau ; chocolat en poudre 15 % (sucre, pâte de cacao) ; farine de blé ; poudre d’œuf ; stabilisants : glycérol, gomme xanthane ; cacao en poudre 2,5 % ; poudre à lever : E450, E500 ; amidon de blé ; conservateur : E202 ; sel. Traces de lait." False

    La question posée est Le mot "soja" apparaît-il dans la composition fournie" ?

    Et si vous étiez intolérant au blé ?

    >>> "blé" in "Sucre ; huile de colza ; eau ; chocolat en poudre 15 % (sucre, pâte de cacao) ; farine de blé ; poudre d’œuf ; stabilisants : glycérol, gomme xanthane ; cacao en poudre 2,5 % ; poudre à lever : E450, E500 ; amidon de blé ; conservateur : E202 ; sel. Traces de lait." True

    La question posée est Le mot "blé" apparaît-il dans la composition fournie" ?

⚙ 01° Utiliser ces instructions dans la console pour comprendre le principe de l'évaluation du booléen obtenu.

>>> a = 12 >>> b = 20 >>> b > a True >>> b < a False >>> b == a False >>> b != a True

On peut stocker le résultat d'une expression booléenne dans une variable. Cette variable contiendra alors soit True, soit False.

Questions

  1. Formuler d'abord en français la question équivalente aux différentes expressions booléennes dont les résultats seront stockés dans les variables c, d, e et f.
  2. >>> a = 12 >>> b = 20 >>> c = b > a >>> d = b < a >>> e = b == a >>> f = b != a
  3. Trouver enfin le contenu stocké dans les différentes variables c, d, e et f. Vérifier à l'aide de la console.

...CORRECTION...

Les questions équivalentes sont :

>>> c = b > a Le contenu de b est-il strictement supérieur au contenu de a ? >>> d = b < a Le contenu de b est-il strictement inférieur au contenu de a ? >>> e = b == a Le contenu de b est-il identique au contenu de a ? >>> f = b != a Le contenu de b est-il différent du contenu de a ?

Pour les valeurs, il suffit de vérifier :

>>> a = 12 >>> b = 20 >>> c = b > a >>> c True >>> d = b < a >>> d False >>> e = b == a >>> e False >>> f = b != a >>> f True
(RAPPELS) 1.2 Expression - Instruction - Affectation

Expression

Une expression est un ensemble de valeurs associées à des opérateurs. L'interpréteur peut évaluer l'expression pour en fournir la valeur.

Une expression ne modifie pas l'état du programme.. Elle fournit simplement une valeur, sans la stocker définitivement.

Dans un programme :

1
"bon" * 2

Ce programme n'a aucun effet, ni en mémoire, ni à l'affichage. Sa ligne est bien simplement une expression.

Dans la console interactive :

>>> "bon" * 2 'bonbon'

Attention, l'affichage obtenu est juste dû au fait qu'on soit dans la console : puisqu'on ne fait rien du résultat de l'expression, il est redirigé vers la sortie console. La même ligne n'aurait aucun effet dans un programme.

Instruction

Une instruction modifie l'état du programme (soit sa mémoire, soit en modifiant l'IHM).

  • L'instruction la plus fondamentale est l'affectation : on crée une variable en mémoire.
  • Dans un programme :

    1
    a = 5

    Dans la console :

  • L'utilisation d'une méthode du module Turtle est bien une instruction : on modifie l'affichage à l'écran et donc l'état de l'interface graphique.
Exemples
>>> "bon" * 2 # EXPRESSION (comme elle est seule et qu'on est dans la console, on obtient son affichage) 'bonbon' >>> a = "bon" * 2 # INSTRUCTION : AFFECTATION >>> print("bon" * 2) # INSTRUCTION (on agit sur l'IHM Console) bonbon

Notez bien que la console Python affiche le résultat d'une expression non redirigée ailleurs.

(RAPPELS) 1.3 - Créer un booléen avec bool()

La fonction native bool() reçoit une donnée quelconque et renvoie True ou False.

!!! A SAVOIR PAR COEUR !!!

En Python, un contenu VIDE ou NUL est évalué à False si on demande un résulat booléen.

Dans tous les autres cas, le résultat est True.

D'où l'intérêt de savoir ce que veut dire nul ou vide pour les différents types de base.

Voici quelques exemples d'évaluation en booléen :

>>> bool(0) # 0 est associé à "vide" False >>> bool(5) # 5 n'est pas "vide" True >>> bool(5.2) # 5.2 n'est pas associé à "vide" True >>> bool(0.0) # 0.0 est associé à "vide" False >>> bool("5") # 0 est associé à "vide" True >>> bool("5.2") # "5.2" n'est pas associé à "vide" True >>> bool("bonjour") # "bonjour" n'est pas associé à "vide" True >>> bool("") # "" est associé à "vide" False

Nous allons pouvoir utiliser ces booléens pour réaliser des instructions conditionnelles : des instructions qui vont être réalisées uniquement si la condition est évaluée à VRAI.

2 - Instruction conditionnelle SI, SINON SI, SINON

C'est l'indentation à droite qui permet à Python de comprendre les actions que vous voulez qu'il réalise si une condition est vérifiée. Il faut donc placer une tabulation ou 4 espaces de suite pour savoir qu’elles sont les instructions rattachées au bloc.

(RAPPELS) 2.1 Instruction conditionnelle

Idée générale

Une instruction conditionnelle permet d'exécuter un bloc d'instructions uniquement si la condition évaluée est vraie (True en Python).

Ci-dessous, un exemple où on change l'appréciation si la note est bonne (if en anglais)

1 2 3 4 5 6
fatigue = "En forme !" appreciation = "Moyen" note = 20 if note > 15: appreciation = "Très bien" fatigue = "Grosse fatigue"
Signification des lignes en français
  • L3 : note référence 20.
  • L4 : si la note est strictement supérieure à 15
  • (L5 tabulée, appartient au if) : alors appreciation référence "Très bien".
  • L6 (pas tabulée, n'appartient pas au if) : fatigue passe à "Grosse fatigue" (sans condition car pas de tabulation).
Importance de la tabulation

La tabulation (4 espaces) permet de signaler à l'intepréteur Python le début et la fin du bloc de la condition. La ligne 6 n'appartient donc pas au bloc : elle sera exécutée que la condition soit vraie ou fausse.

On peut rendre le code plus clair pour un débutant en utilisant des lignes vides :

1 2 3 4 5 6 7 8
fatigue = "En forme !" appreciation = "Moyen" note = 20 if note > 15: appreciation = "Très bien" fatigue = "Grosse fatigue"
Déroulé pour note = 20

L1 - L2 - L3 - L4 (avec condition vraie) - L5 - L6 - fin

1 2 3 4 5 6
fatigue = "En forme !" appreciation = "Moyen" note = 20 if note > 15: # Vrai pour une note de 20 appreciation = "Très bien" # donc on effectue cette ligne fatigue = "Grosse fatigue"
Déroulé pour note = 10

L1-L2-L3-L4 (avec condition fausse) - L6 - fin

1 2 3 4 5 6
fatigue = "En forme !" appreciation = "Moyen" note = 14 if note > 15: # Faux pour une note de 14 appreciation = "Très bien" # donc on n'effectue pas cette ligne fatigue = "Grosse fatigue"
2.2 Instruction conditionnelle : structure générale

Quelque soit le langage, on retrouve toujours une structure qui ressemble à ceci :

1 2 3 4 5 6 7 8 9 10 11 12 13 14
# BLOC A (un seul, obligatoire) SI une expression booléenne A est vraie Instruction A1 Instruction A2 # BLOC B (0 ou + : optionnel) SINON SI une expression booléenne B est vraie Instruction B1 Instruction B2 # BLOC C (0 ou 1 : optionnel unique) SINON (dans tous les autres cas) Instruction C1 Instruction C2

Nombre de blocs

  • Un unique bloc SI et il doit toujours être en première position
  • 0, 1, 2 ou autant de blocs SINON SI que vous voulez
  • 0 ou 1 bloc SINON et il doit toujours être en dernière position : c'est le bloc par défaut. Si aucun autre n'a été activé, on prend celui-ci.
2.3 Instruction conditionnelle : un seul bloc exécuté

A SAVOIR IMPERATIVEMENT

L'interpréteur Python n'exécute que l'un des blocs A, B ou C d'une structure if-elif-else.

Il exécute les instructions du bloc de la première expression évaluée à True puis quitte la structure même si les autres expressions sont vraies également.

Un exemple de déroulement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Instructions Avant 1 Instructions Avant 2 # BLOC A (un seul, obligatoire) if note > 11: Instruction A1 Instruction A2 Instruction A3 # BLOC B (0 ou + : optionnel) elif note < 9: Instruction B1 Instruction B2 Instruction B3 # BLOC C (0 ou 1 : optionnel unique) else: Instruction C1 Instruction C2 Instructions Après 1 Instructions Après 2

Exemple avec note valant 15.

C'est le bloc A qui va s'activer car note > 11 est évaluée à True.

Il exécute L1-L2-L5-L6-L7-L8-L21-L22.

Exemple avec note valant 5.

C'est le bloc B qui va s'activer car le bloc A ne sera pas activé et note < 9 est évaluée à True.

Il exécute L1-L2-L5-L11-L12-L13-L14-L21-L22.

Exemple avec note valant 9.

C'est le bloc C qui va s'activer car le bloc A ne sera pas activé, le bloc B non plus (9 n'est pas strictement inférieur à 9) et le else ne possède jamais de condition : si on y arrive, on le déclenche toujours.

Il exécute L1-L2-L5--L11-L17-L8-L19-L21-L22.

⚙ 02° Tester la fonction suivante en lui fournisant différents paramètres entre 1980 et 2010 par exemple.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def creer_message(reponse:int) -> str: """Renvoie un string en fonction de la réponse de l'utilisateur""" annee_creation_python = 1991 if reponse > annee_creation_python: message = f"Python a été créé avant {reponse}" elif reponse < annee_creation_python: message = f"Python a été créé après {reponse}" else: message = f"Oui, Python est sorti pour la première fois en {reponse}" return message for _ in range(3): tentative = int(input("En quelle année a été créé le langage Python ? ")) m = creer_message(tentative) print(m)
En quelle année a été créé le langage Python ? 1981 ??? En quelle année a été créé le langage Python ? 1991 ??? En quelle année a été créé le langage Python ? 2021 ???

Questions :

  1. Quel est mot-clé correspondant à SI en Python ?
  2. Quel est mot-clé correspondant à SINON SI en Python ?
  3. Quel est mot-clé correspondant à SINON en Python ?
  4. Compléter les lignes suivies par l'interpréteur si on tape 1981 en ligne 13 :
  5. L13(appel en envoyant 1981) - ... - L13(réception de la réponse).

  6. Compléter les lignes suivies par l'interpréteur si on tape 1991 en ligne 13 :
  7. L13(appel en envoyant 1991) - ... - L13(réception de la réponse).

  8. Compléter les lignes suivies par l'interpréteur si on tape 2021 en ligne 13 :
  9. L13(appel en envoyant 2021) - ... - L13(réception de la réponse).

...CORRECTION...

  1. Le SI se code avec le mot-clé if.
  2. Le SINON SI se code avec le mot-clé elif.
  3. Le SINON (tout court) se code avec le mot-clé else.
  4. Lignes suivies par l'interpréteur si on tape 1981 
  5. L1 (reponse = 1981) - L3 - L4(False) - L6(True) - L7 - L10

  6. Lignes suivies par l'interpréteur si on tape 1991 
  7. L1 (reponse = 1991) - L3 - L4(False) - L6(False) - L8 - L9 - L10

  8. Lignes suivies par l'interpréteur si on tape 2021 
  9. L1 (reponse = 2021) - L3 - L4(True) - L5 - L10

⚙ 03° Quelques questions générales :

  1. Pourquoi ne place-t-on pas de condition derrière else, contrairement à if ou elif ?
  2. Que trouve-t-on à la fin de chacune des lignes contenant if, elif ou else ?
  3. Comment sont positionnées les instructions conditionnelles par rapport aux mots-clés précédents ?
  4. L'interpréteur continue-t-il à effectuer le reste des tests à partir du moment où il valide l'un des blocs d'instructions ?

...CORRECTION...

  1. else signifie SINON. C'est le cas par défaut, celui qu'on effectue si aucun des tests précédents n'a fonctionné. Il n'a donc aucune condition : si on parvient à lui, c'est que le reste a échoué.
  2. On finit chaque condition par  : .
  3. On retrouve la structure d'une fonction ou d'un for : on décale de 4 espaces pour signaler les limites du bloc.
  4. L'interpréteur ne traitera bien que l'un des blocs. Dès qu'il rencontre une expression évaluée VRAIE, il exécute les instructions du bloc correspondant puis quitte la structure conditionnelle SANS tester les possibilités restantes.

⚙ 04° Compléter la fonction appreciation() ci-dessous. Elle doit renvoyer :

  • "Bien" si le paramètre note est strictement supérieur à 13,
  • "Insuffisant" si le paramètre est inférieur à 9 et
  • "Moyen" sinon.

Contrainte : on ne veut qu'un seul return.

1 2 3 4 5 6 7 8
def appreciation(note): """Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante """ pass

...CORRECTION...

Version un seul endroit où on gère l'envoi de la réponse.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def appreciation(note): """Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante """ if note > 13: app = "Bien" elif note < 9: app = "Insuffisant" else: app = "Moyen" return app

⚙ 05° Lire les autres versions proposées et répondre à la question finale.

Quelqu'un propose cette version valide n°2 : dès qu'on sait quoi répondre, on répond.

Version 2 valide (plusieurs sorties)

1 2 3 4 5 6 7 8 9 10 11 12 13
def appreciation_v2(note): """Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante """ if note > 13: return "Bien" elif note < 9: return "Insuffisant" else: return "Moyen"

AVANTAGE : cette structure permet au lecteur humain de savoir immédiatement la réponse qui va être donner dans ce cas.

DESAVANTAGE : il va être plus difficile de vérifier et surveiller les réponses de cette fonction. C'est comme surveiller un batiment : c'est plus facile de contrôler les sorties s'il n'y a qu'une seule sortie.

Version 3 valide (plusieurs sorties, pas de else final)

Une autre personne pense qu'on peut encore faire plus rapide en supprimant le else final avec cette version 03. Cette version 03 est valide également puisque si on arrive en ligne 12, c'est que les autres return n'ont pas été rencontrés.

1 2 3 4 5 6 7 8 9 10 11 12
def appreciation_v3(note): """Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante """ if note > 13: return "Bien" elif note < 9: return "Insuffisant" return "Moyen"

AVANTAGE : on gagne une ligne. Bof.

Version 4 incorrecte (une sortie, pas de else final)

Un enthousiaste pense du coup à modifier la première version et propose une version 04 (incorrecte attention).

1 2 3 4 5 6 7 8 9 10 11 12 13
def appreciation_v4(note): """Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante """ if note > 13: app = "Bien" elif note < 9: app = "Insuffisant" app = "Moyen" return app

Question

Expliquer pourquoi on peut se passer du else dans la version 3 mais pas dans la version 4.

...CORRECTION...

La version 03 fonctionne car dès qu'on rencontre un return, on répond et on sort de la fonction.

Si on atteint les lignes 9 ou 11, on quitte donc la fonction. Cela veut dire qu'on ne peut arriver à la ligne 12 que si la note n'est ni supérieure à 13, ni inférieure à 9.

Par contre, dans la version 04, il ne place pas de return. Cela veut dire que même si on rentre dans l'un des blocs if ou elif, on affectera la variable app mais on ne sortira pas de la fonction.

Du coup, on va simplement atterir ligne 12 à chaque fois et écraser la version précédente de notre variable !

Ici, le else est donc obligatoire.

2.4 Instruction conditionnelle et fonction

RAPPEL : on sort d'une fonction et on fait disparaître l'espace des noms dédié dès qu'on rencontre un return.

Version propre avec une seule "porte de sortie"
  • AVANTAGE : plus facile de surveiller la correction de la fonction (le fait que la fonction réponde toujours correctement)
  • DESAVANTAGE : il faut stocker la réponse dans une variable et lire ensuite séquentiellement la fonction jusqu'à trouver l'unique sortie.
  • 1 2 3 4 5 6 7 8
    def appreciation(note:int) -> str: if note > 13: app = "Bien" elif note < 9: app = "Insuffisant" else: app = "Moyen" return app
Version avec plusieurs "portes de sortie"
  • DESAVANTAGE : moins facile à surveiller (plusieurs portes de sortie à contrôler).
  • AVANTAGE : on n'a pas besoin en tant que lecteur humain de continuer à lire le reste du code lorsqu'on rencontre une sortie.
  • 1 2 3 4 5 6 7
    def appreciation(note:int) -> str: if note > 13: return "Bien" elif note < 9: return "Insuffisant" else return "Moyen"

    Ou encore :

    1 2 3 4 5 6
    def appreciation(note:int) -> str: if note > 13: return "Bien" elif note < 9: return "Insuffisant" return "Moyen"
Exemple

Voici quelques autres exemples d'utilisation pour mieux comprendre comment structurer vos demandes :

  • La fonction trop_gentil() qui renvoie une note augmentée de +2 si la note d'entrée est inférieure à 10 et, sinon, +1 pour une note inférieure à 19.
  • 1 2 3 4 5 6
    def trop_gentil(note:int) -> int: if note < 10: note = note + 2 elif note < 19: note = note + 1 return note
  • La fonction beaucoup_trop_gentil() qui renvoie une note augmentée de +5 si la note d'entrée est inférieure à 10 et, sinon, +3 dans les autres cas. La fonction ne doit jamais renvoyer de notes supérieures à 20 : on impose L8-L9 cette condition juste avant de renvoyer la réponse par l'unique porte de sortie.
  • 1 2 3 4 5 6 7 8 9 10
    def beaucoup_trop_gentil(note:int) -> int: # Un return unique if note < 10: note = note + 5 else: note = note + 3 # Vérification avant envoi if note > 20: note = 20 return note
  • La fonction beaucoup_trop_gentil() pas top car elle possède plusieurs "portes de sortie" : on se retrouve à faire du copier-coller de la vérification des valeurs des sorties (L6-L7 et L12-L13). La correction de la fonction est plus compliquée à faire.
  • 1 2 3 4 5 6 7 8 9 10 11 12 13 14
    def beaucoup_trop_gentil(note:int) -> int: # Deux return if note < 10: note = note + 5 # Vérification avant envoi if note > 20: note = 20 return note else: note = note + 3 # Vérification avant envoi if note > 20: note = 20 return note

Passons à la pratique :

✎ 06° Compléter la fonction traduction() ci-dessous. Elle doit renvoyer :

  • "vert" si le paramètre color est "green",
  • "rouge" pour "red",
  • "bleu" pour "blue",
  • "jaune" pour "yellow".
  • si la couleur est inconnue, elle doit répondre "traduction inconnue pour cette couleur".

Remarque : on veut une structure if-elif if-else. Mais nous sommes d'accord qu'un dict aurait mieux fait l'affaire !

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def traduction(color): """Renvoie un string correspondant à la traduction de la couleur ANG -> FR :: param color(str) :: une couleur en anglais :: return (str) :: la traduction en français du string précédent .. exemples .. >>> traduction('green') 'vert' >>> traduction('grine') 'traduction inconnue pour cette couleur' """ couleur = "traduction inconnue pour cette couleur" return couleur

3 - Prédicat : fonction renvoyant un booléen

3.1 Opérateurs == et =

Attention à ne pas confondre

  • l'opérateur d'égalité de contenu ==
  • l'opérateur d'affectation =

Avec a == b, l'interpréteur comprend qu'il doit tester l'égalité des variables a et b. Il va donc évaluer cette expression et obtenir vrai si les deux contenus sont les mêmes.

Avec a = b, l'interpréteur comprend qu'il faut stocker b dans la variable a. On génère donc un alias.

3.2 FONCTION : Prédicat

Forme typique de prédicat

On peut nommer de cette façon une fonction qui renvoie toujours un booléen : elle répondra soit True soit False.

On parle de prédicat puisque la fonction prédit une propriété à partir des paramètres reçus.

Ce cas de figure est très courant en informatique : créer un prédicat ne requiert donc forcément pas d'utiliser un if : il suffit de fournir l'expression qu'on veut évaluer derrière votre return.

Exemple avec une expression qui évalue si une note de 10 permet de valider un semestre :

>>> note = 9 >>> note >= 10 False >>> note = 12 >>> note >= 10 True

Le prédicat validant le semestre donnerait simplement ceci :

1 2 3
def est_valide(note:int) -> bool: """Prédicat qui renvoie True si la note est supérieure ou égale à 10""" return note >= 10
La version à éviter tant que c'est possible

La version ci-dessous est valide également mais est à éviter si possible : elle revient à dire "si c'est vrai, dis que c'est vrai, sinon, dis que c'est faux". Un peu lourd. Et l'oubli du else est très courant : on finit par avoir une fonction qui dit bien quand c'est vrai mais qui ne répond rien quand c'est faux.

1 2 3 4 5 6
def est_valide(note:int) -> bool: """Prédicat qui renvoie True si la note est supérieure ou égale à 10""" if note >= 10: return True else: return False

⚙ 07° Que va renvoyer la fonction est_valide() si le paramètre note vaut 7 ?

1 2 3
def est_valide(note:int) -> bool: """Prédicat qui renvoie True si la note est supérieure ou égale à 10""" return note >= 10

...CORRECTION...

note >= 10

7 >= 10

False

⚙ 08° Un élève propose cette version : est-elle bonne, fausse, correcte mais inutilement longue ?

1 2 3 4 5 6
def est_valide(note:int) -> bool: """Prédicat qui renvoie True si la note est supérieure ou égale à 10""" if note >= 10: return True else: return False

...CORRECTION...

Bonne mais inutilement longue.

Si vous préférez cette version pendant quelques temps, utilisez la. Vous aurez les points.

Mais dès que vous serez à l'aise, passez plutôt à la version courte return note >= 10.

⚙ 09° Compléter la fonction-prédicat comparer() pour qu'elle renvoie True si les deux paramètres sont égaux. Aucune condition de type sur les deux paramètres.

1 2 3
def comparer(proposition, mystere) -> bool: """Prédicat qui renvoie True si les deux paramètres sont égaux""" pass

...CORRECTION...

Il est probable que vous ayez tapé quelque chose qui ressemble à cela :

1 2 3 4 5 6
def comparer(proposition, mystere) -> bool: """Prédicat qui renvoie True si les deux paramètres sont égaux, False sinon""" if proposition == mystere: return True else: return False

Si vous avez mémorisé l'histoire du return qui provoque une sortie de la fonction, vous avez même surement tapé ceci :

1 2 3 4 5
def comparer(proposition, mystere) -> bool: """Prédicat qui renvoie True si les deux paramètres sont égaux, False sinon""" if proposition == mystere: return True return False

Et pourtant, il a eu encore une manière plus courte de répondre (les explications sont ci-dessous si vous ne comprennez pas bien comment ça fonctionne) :

1 2 3
def comparer(proposition, mystere) -> bool: """Renvoie True si les deux paramètres sont égaux, False sinon""" return proposition == mystere

4 - If sans condition booléenne ?

Avec un IF, on exécute un bloc tabulé si l'expression booléenne est True.

1 2 3 4
if expression_booléenne_1: fait un truc elif expression_booléenne_2: fait autre chose

Mais que se passe-t-il si on place une expression NON booléenne derrière le if ou le elif ?

4.1 Instruction conditionnelle : condition non booléenne

Cas d'une expression booléenne

Lorsque l'interpréteur Python lit un if ou un elif, il s'attend à trouver une expression booléenne derrière.

Exemple : if a >= 0:

Ici, l'expression est bien une expression booléenne.

Cas d'une expression non booléenne

Il peut arriver par contre que l'expression fournie ne soit pas une expression booléenne.

Exemple : if a:

Python ne va alors pas s'embêter : il va chercher à l'interpréter comme un booléen, comme si vous aviez tapé ceci :

Exemple : if bool(a):

Ainsi :

  • Si a est 0 ou 0.0 ou "" ou [] ou () ou {} ou None, a sera équivalent à un False.
  • Dans tous les autres cas, a sera équivalent à True.

⚙ 10° Donner les contenus des variables r1, r2, r3, r4 après exécution du programme ci-dessous.

1 2 3 4 5 6 7 8 9 10
def alors(n): reponse = 10 if n: reponse = 20 return reponse r1 = alors(45) r2 = alors("") r3 = alors("bonjour') r4 = alors([])

...CORRECTION...

r1 : avec le premier envoi, la condition de la ligne 3 est évaluée à True, et la fonction renvoie donc 20.

r2 : avec le premier envoi, la condition de la ligne 3 est évaluée à False car la variable n'est qu'une chaîne de caractères vide, et la fonction renvoie donc 10.

r3 : avec le premier envoi, la condition de la ligne 3 est évaluée à True, et la fonction renvoie donc 20.

r4 : avec le premier envoi, la condition de la ligne 3 est évaluée à False car la variable n'est qu'un tableau vide, et la fonction renvoie donc 10.

4.2 Instruction conditionnelle : tableau vide

On peut agir en fonction de l'état VIDE ou NON VIDE d'un type construit en utilisant une simple instruction conditionnelle.

Voici comment agir de façon différente si le tableau est NON VIDE ou s'il est VIDE :

1 2 3 4 5
if tab: # si tab est NON VIDE actions_si_le_tableau_n_est_pas_vide else: # sinon, c'est que tab est VIDE actions_si_le_tableau_est_vide

Le mot-clé not permet d'inverser la valeur booléenne : vrai devient faux, et faux devient vrai. On peut alors demander ainsi d'agir sur un tableau VIDE :

1 2 3 4 5
if not tab: # tab est vide (car tab évalué à False, not tab à True) actions_si_le_tableau_est_vide else: # sinon, c'est que tab est vide actions_si_le_tableau_est_vide

CONCLUSION :

Si t fait référence à un type construit :

  • if t     se traduit par "Si t n'est PAS VIDE".
  • if not t se traduit par "Si t est VIDE".

On peut maintenant réaliser une fonction qui peut nous aider à gérer les réservations d'un restaurant.

✎ 11-difficile° Donner et expliquer le contenu des variables possible et numero si elle existe.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Déclaration des fonctions def reste_une_table_vide(tables:list) -> bool: """Prédicat qui renvoie True s'il reste une table non reservée""" for i in range(len(tables)): # pour chaque indice possible dans le tableau if not tables[i]: # si la table i est vide return True return False def trouver_une_table(tables:list) -> int: """Renvoie l'indice de la première table non réservée""" for i in range(len(tables)): # pour chaque indice possible dans le tableau if not tables[i]: # si la table i est vide return i # Instructions du programme principal reservations = ['Alice', '', 'Bob', '', '', 'Charlie'] if reste_une_table_vide(reservations): numero = trouver_une_table(reservations)

Le programme commence en ligne 21, le reste étant de la déclaration de fonctions.

21 22 23 24
reservations = ['Alice', '', 'Bob', '', '', 'Charlie'] if reste_une_table_vide(reservations): numero = trouver_une_table(reservations)

Pour répondre, il faudra suivre le déroulé exact du programme, expliquer lors des appels ce que contient tel ou tel paramètre... Tenter de comprendre le programme dans sa globalité, sans suivre réellement son cheminement n'a que peu de chance d'aboutir. Séquentialité.

Demandez de l'aide s'il le faut, ce n'est pas si facile que cela lorsqu'on vient de découvrir ces notions.

5 - Exercices

6 - FAQ

On peut tester le type des variables ?

Oui. Les deux manières de faire les plus courantes sont fournies ci-dessous :

Première méthode : tester le type de la variable.

>>> a = 5.0 >>> type(a) == float True >>> type(a) == int False >>> type(a) == str False >>> a = "5.0" >>> type(a) == float False >>> type(a) == int False >>> type(a) == str True

Deuxième façon de faire : utiliser la fonction native isinstance.

>>> a = 5 >>> isinstance(a, float) False >>> isinstance(a, int) True >>> isinstance(a, str) False

7 -

Maintenant que vous avez vu ou revu les notions d'instructions conditionnelles et de boucles bornées, voyons comment on peut les utiliser pour réaliser des choses plus concrêtes qu'un simple calcul.

La blague du jour : Le problème de la logique des informaticiens :

Ma mère : « Mon chéri, peux-tu aller au supermarché et me ramener une bouteille de lait. Si ils ont des œufs, prends en 6 ».

Je suis revenu avec 6 bouteilles de lait.

Ma mère a dit : « Pourquoi as-tu pris 6 bouteilles de lait ?»

J’ai répondu : « Car ils avaient des œuf … »

conclusion Logique ou pas ?

Pour comprendre cela, il faut bien entendu suivre ces instructions à la lettre :

  • Si il n'y a d'oeuf, prendre 1 bouteille de lait.
  • Si il y a des oeufs, prendre 6 bouteilles de lait

L'air de rien comprendre cela permet de comprendre qu'un ordinateur ne fait que suivre séquentiellement les instructions qu'on lui impose. Il ne tente jamais d'y mettre du sens et de tenter de comprendre ce que vous voulez réellement. Il exécute. Point.

Activité publiée le 01 11 2020
Dernière modification : 20 07 2024
Auteur : ows. h.