đ Expressions boolĂ©ennes
- Expressions booléennes
- if
- elif
- else
- Comparaison
- Imbrication
- DRY
- Forme compacte
- Validation raise/try/except
- Trace
- Activités
- *match/case*
Une expression booléenne est une expression qui évalue à une valeur de vérité (bool), c'est-à -dire soit True (vrai) soit False (faux).
Elles sont utilisées pour prendre des décisions dans le code, comme dans les instructions conditionnelles (if, elif, else) et les boucles (while, for).
Les opérateurs de comparaison sont utilisés pour comparer deux valeurs.
Voici les principaux opérateurs de comparaison en Python :
| Opérateur | Description | Exemple | Résultat |
|---|---|---|---|
| == | Ăgal Ă | a == b | True si Ă©gaux |
| != | Différent de | a != b | True si différents |
| < | Inférieur à | a < b | True si a plus petit |
| <= | Inférieur ou égal à | a <= b | True si a plus petit ou égal |
| > | Supérieur à | a > b | True si a plus grand |
| >= | Supérieur ou égal à | a >= b | True si a plus grand ou égal |
| and | ET logique | a and b | True si les deux sont True |
| or | OU logique | a or b | True si au moins un est True |
| not | NON logique | not a | Inverse la valeur booléenne |
a = 5
b = 10
print(a < b) # Affiche True
print(a == b) # Affiche False
print(a + 5 >= b - max(1, min(4, a, 6), 5)) # Affiche True, explications ci-dessous!
Les 2 opĂ©randes dâun opĂ©rateur de comparaison peuvent ĂȘtre le rĂ©sultat de l'Ă©valuation dâexpressions.
Python Ă©value lâexpression selon la prioritĂ© des opĂ©rateurs, en remplaçant chaque sous-expression par sa valeur rĂ©sultante.
Voici comment Python Ă©value lâinstruction #5, Ă©tape par Ă©tape :
print(a + 5 >= b - max(1, min(4, a, 6), 5)) # Instruction originale
print(5 + 5 >= b - max(1, min(4, 5, 6), 5)) # Remplace 'a' par sa valeur
print(10 >= b - max(1, min(4, 5, 6), 5)) # Calcule la somme de '5 + 5'
print(10 >= 10 - max(1, min(4, 5, 6), 5)) # Remplace 'b' par sa valeur
print(10 >= 10 - max(1, 4, 5)) # La fonction min(...) doit ĂȘtre rĂ©solue avant la fonction max(...)
print(10 >= 10 - 5) # La fonction max(...) est résolue
print(10 >= 5) # L'opération >=
print(True) # Affiche "True" dans la console
Les opérateurs logiques sont utilisés pour combiner plusieurs expressions booléennes.
Ils sont inclus dans le tableau des expressions booléennes ci-dessus (and, or, not).
La priorité des opérateurs détermine l'ordre dans lequel les opérations sont effectuées dans une expression.
En Python, la priorité des opérateurs est la suivante (de la plus haute à la plus basse) :
- ParenthĂšses
() - Opérateurs de comparaison (
==,!=,<,<=,>,>=) - Opérateur
not - Opérateur
and - Opérateur
or
Un ordre plus exhaustif des priorités des opérateurs est disponible ici dans l'aide-mémoire.
a = 5
b = 10
c = 15
print(a < b and b < c) # ĂvaluĂ© comme (a < b) and (b < c), affiche True
print(a < b or b > c) # ĂvaluĂ© comme (a < b) or (b > c), affiche True
print(not a < b) # ĂvaluĂ© comme not (a < b), affiche False
# On peut utiliser des parenthÚses pour modifier l'ordre d'évaluation :
print(a < b or b > c and a == 5) # ĂvaluĂ© comme a < b or (b > c and a == 5), affiche True
print((a < b or b > c) and a == 5) # ĂvaluĂ© comme (a < b or b > c) and a == 5, affiche True
On peut stocker le résultat d'une expression booléenne dans une variable pour une utilisation ultérieure.
a = 5
b = 10
est_plus_petit = a < b # est_plus_petit sera True
est_egal = a == b # est_egal sera False
print(est_plus_petit) # Affiche True
print(est_egal) # Affiche False
Les explications de cette section étaient-elles claires ?
C'est bien beau, ça, les expressions booléennes, mais à quoi ça sert?
đ Elles servent principalement Ă contrĂŽler le flux d'exĂ©cution du programme,
c'est-Ă -dire Ă dĂ©cider quelles parties du code doivent ĂȘtre exĂ©cutĂ©es en fonction de certaines conditions.
Voici un exemple simple d'instruction conditionnelle en Python :
age = 18
if age >= 18 :
print("Vous ĂȘtes majeur.")
Dans cet exemple, l'instruction if vérifie si la variable age est supérieure ou égale à 18.
Si c'est le cas (si la condition est True), le code indentĂ© sous l'instruction if est exĂ©cutĂ©, affichant "Vous ĂȘtes majeur.".
Si la condition est False, le code indenté n'est pas exécuté.
En Python, l'indentation (les espaces ou tabulations avant une ligne de code) est cruciale pour définir les blocs de code.
Le code qui doit ĂȘtre exĂ©cutĂ© conditionnellement doit ĂȘtre indentĂ© sous l'instruction if.
Par exemple :
if condition :
# Code indenté, exécuté si la condition est True
faire_quelque_chose_conditionnel()
faire_autre_chose_conditionnel()
# Code non indenté, exécuté indépendamment de la condition
faire_autre_chose_en_tout_temps()
Exemple d'erreur courante due Ă une mauvaise indentation :
if condition :
faire_quelque_chose() # Erreur : cette ligne doit ĂȘtre indentĂ©e
Exemple concret :
age = 20
if age >= 18 :
print("Vous ĂȘtes majeur.")
print("Vous avez le droit de vote!")
print("Un grand pouvoir implique de grandes responsabilités.")
print("Bienvenue!") # Toujours exécuté, indépendamment de l'ùge
Les explications de cette section étaient-elles claires ?
Non!
elif est la contraction de "else if", qui signifie "sinon si".
Elle permet de vérifier une autre condition si la premiÚre condition dans l'instruction if est False.
Par exemple :
age = 16
if age >= 18 :
print("Vous ĂȘtes majeur.")
elif age >= 13 :
print("Vous ĂȘtes adolescent.")
On peut avoir plusieurs clauses elif pour vérifier plusieurs conditions différentes.
Par exemple :
age = 10
if age >= 18 :
print("Vous ĂȘtes majeur.")
elif age >= 13 :
print("Vous ĂȘtes adolescent.")
elif age >= 3 :
print("Vous ĂȘtes un enfant.")
L'ordre des conditions est important.
Les conditions sont évaluées de haut en bas, et la premiÚre condition qui est True déclenche l'exécution du bloc de code correspondant.
Par exemple, dans le code suivant, la condition age >= 13 sera toujours True pour tous les adultes, et la condition age >= 18 ne sera jamais atteinte :
age = 21
if age >= 13 :
print("Vous ĂȘtes adolescent.")
elif age >= 18 :
print("Vous ĂȘtes majeur.")
Pour éviter cela, il faut toujours commencer par la condition la plus restrictive (la plus élevée) et descendre vers les conditions moins restrictives :
age = 21
if age >= 18 :
print("Vous ĂȘtes majeur.")
elif age >= 13 :
print("Vous ĂȘtes adolescent.")
elif sans ifUne clause elif doit toujours ĂȘtre prĂ©cĂ©dĂ©e d'une instruction if.
Par exemple, le code suivant est incorrect et provoquera une erreur de syntaxe :
age = 16
elif age >= 13 : # Erreur : 'elif' sans 'if'
print("Vous ĂȘtes adolescent.")
Les explications de cette section étaient-elles claires ?
else signifie "sinon".
Elle permet de définir un bloc de code qui sera exécuté si toutes les conditions précédentes (if et elif) sont False.
Par exemple :
age = 10
if age >= 18 :
print("Vous ĂȘtes majeur.")
elif age >= 13 :
print("Vous ĂȘtes adolescent.")
else :
print("Vous ĂȘtes un enfant.")
Dans cet exemple, si age est infĂ©rieur Ă 13, le message "Vous ĂȘtes un enfant." sera affichĂ©.
La clause else est souvent utilisée à la fin d'une série d'instructions if et elif pour capturer tous les cas non couverts par les conditions précédentes.
Par exemple :
score = 85
if score >= 90 :
print("Excellent")
elif score >= 75 :
print("Bien")
elif score >= 50 :
print("Passable")
else :
print("Ăchec")
Contrairement Ă if et elif, la clause else ne prend pas de condition.
Elle est simplement exécutée si toutes les conditions précédentes sont False. Par exemple, le code suivant est incorrect et provoquera une erreur de syntaxe :
score = 85
if score >= 90 :
print("Excellent")
elif score >= 75 :
print("Bien")
elif score >= 50 :
print("Passable")
else score < 50 : # Erreur : 'else' ne doit pas avoir de condition
print("Ăchec")
Il est possible d'utiliser else directement aprĂšs un if, sans avoir besoin de elif.
Par exemple :
age = 20
if age >= 18 :
print("Vous ĂȘtes majeur.")
else :
print("Vous ĂȘtes mineur.")
Les structures conditionnelles (if/elif/else, match/case) peuvent ĂȘtre utilisĂ©es Ă l'intĂ©rieur de fonctions.
Exemple 1 â if/else simple :
def est_pair(n):
if n % 2 == 0:
return True # Faire modulo 2 sur un nombre pair donne toujours 0!
else:
return False
a = 33
b = 52
print(f"{a} est un nombre pair : {est_pair(a)}")
print(f"{b} est un nombre pair : {est_pair(b)}")
33 est un nombre pair : False
52 est un nombre pair : True
Exemple 2 â if/else avec paramĂštre optionnel et calcul par palier :
La fonction suivante calcule la paie brute d'un employé. Elle accepte un troisiÚme paramÚtre optionnel pour activer le calcul des heures supplémentaires au taux double.
def calculer_paie_brute(nb_heures, taux_horaire, temps_double_apres_40_heures=False):
salaire = nb_heures * taux_horaire
if temps_double_apres_40_heures and nb_heures >= 40:
nb_heures_temps_supp = nb_heures - 40
salaire = salaire + nb_heures_temps_supp * taux_horaire * 2
return salaire
nb_heures = 45
taux_horaire = 20
print(f"Calcul de la paie brute pour {nb_heures} heures Ă un taux horaire de {taux_horaire}$/h.")
print(f" Avec le temps > 40 payé au taux doublé : {calculer_paie_brute(nb_heures, taux_horaire, True)}$")
print(f" Avec le temps > 40 payé au taux régulier : {calculer_paie_brute(nb_heures, taux_horaire)}$")
Calcul de la paie brute pour 45 heures Ă un taux horaire de 20$/h.
Avec le temps > 40 payé au taux doublé : 1100$
Avec le temps > 40 payé au taux régulier : 900$
Exemple 3 â if/elif/else avec trois listes parallĂšles :
On peut stocker plusieurs valeurs dans des listes parallĂšles et appeler notre fonction sur chaque Ă©lĂ©ment. Voici une liste d'Ă©lĂ©ments du tableau pĂ©riodique avec leur masse atomique (en u.m.a.) et leur nombre de protons. On veut classifier la stabilitĂ© de chaque noyau en fonction du rapport entre sa masse atomique et son nombre de protons â un indicateur simplifiĂ© du ratio neutrons/protons :
def stabilite_noyau(masse_atomique, nb_protons):
"""
Classifie la stabilité d'un noyau selon le ratio neutrons/protons.
ParamĂštres :
masse_atomique (int) : Nombre de masse de l'élément (protons + neutrons).
nb_protons (int) : Nombre de protons dans le noyau.
Retourne :
str : "stable", "légÚrement instable" ou "trÚs instable".
"""
nb_neutrons = masse_atomique - nb_protons
ratio = nb_neutrons / nb_protons
if ratio <= 1.1 :
return "stable"
elif ratio <= 1.5 :
return "légÚrement instable"
else :
return "trĂšs instable"
masses_atomiques = [1,4,7,12,14,16]
symboles = ["H","He","Li","C","N","O"]
nb_protons = [1,2,3,6,7,8]
print(f"{symboles[0]} (masse {masses_atomiques[0]}) - stabilité : {stabilite_noyau(masses_atomiques[0], nb_protons[0])}")
print(f"{symboles[1]} (masse {masses_atomiques[1]}) - stabilité : {stabilite_noyau(masses_atomiques[1], nb_protons[1])}")
print(f"{symboles[2]} (masse {masses_atomiques[2]}) - stabilité : {stabilite_noyau(masses_atomiques[2], nb_protons[2])}")
print(f"{symboles[3]} (masse {masses_atomiques[3]}) - stabilité : {stabilite_noyau(masses_atomiques[3], nb_protons[3])}")
print(f"{symboles[4]} (masse {masses_atomiques[4]}) - stabilité : {stabilite_noyau(masses_atomiques[4], nb_protons[4])}")
print(f"{symboles[5]} (masse {masses_atomiques[5]}) - stabilité : {stabilite_noyau(masses_atomiques[5], nb_protons[5])}")
H (masse 1) - stabilité : stable
He (masse 4) - stabilité : stable
Li (masse 7) - stabilité : légÚrement instable
C (masse 12) - stabilité : stable
N (masse 14) - stabilité : stable
O (masse 16) - stabilité : stable
đ On remarque qu'on rĂ©pĂšte 6 fois la mĂȘme instruction print en changeant seulement l'index.
C'est exactement le genre de répétition qu'une boucle for éliminera en quelques lignes, vous verrez ça bientÎt!
Les explications de cette section étaient-elles claires ?
if if if vs if elif else â ce n'est pas la mĂȘme chose!C'est l'une des erreurs les plus frĂ©quentes chez les dĂ©butants :
utiliser plusieurs if indĂ©pendants lĂ oĂč un if/elif/else serait nĂ©cessaire.
La différence est fondamentale et peut avoir des impacts sur les performances.
Prenons cet exemple avec score = 95 :
# Version avec des if if if
score = 95
if score >= 90 :
print("Excellent") # â
Exécuté (95 >= 90 est True)
if score >= 75 :
print("Bien") # â
Exécuté (95 >= 75 est True)
if score >= 50 :
print("Passable") # â
Exécuté (95 >= 50 est True)
else :
print("Ăchec") # âïž Bloc ignorĂ© (car la condition score >= 50 a donnĂ© True)
Résultat affiché :
Excellent
Bien
Passable
đ Avec des if indĂ©pendants, Python Ă©value chaque condition sĂ©parĂ©ment, de haut en bas, sans jamais s'arrĂȘter. Comme les 3 conditions sont True pour score = 95, les 3 blocs sont exĂ©cutĂ©s. Ce n'est presque certainement pas ce qu'on voulait! Il aurait Ă©tĂ© prĂ©fĂ©rable que Python arrĂȘte dâĂ©valuer les autres conditions dĂšs quâil trouve une condition donnant True.
if elif else# Version avec if elif else
score = 95
if score >= 90 :
print("Excellent") # â
ExĂ©cutĂ© (95 >= 90 est True) â Python arrĂȘte ici
elif score >= 75 :
print("Bien") # âïž Bloc ignorĂ© (car une condition d'un bloc prĂ©cĂ©dent a donnĂ© True)
elif score >= 50 :
print("Passable") # âïž Bloc ignorĂ© (car une condition d'un bloc prĂ©cĂ©dent a donnĂ© True)
else :
print("Ăchec") # âïž Bloc ignorĂ© (car une condition d'un bloc prĂ©cĂ©dent a donnĂ© True)
Résultat affiché :
Excellent
đ Avec if/elif/else, dĂšs qu'une condition est True, Python exĂ©cute le bloc correspondant et saute immĂ©diatement le reste : les autres conditions ne sont jamais Ă©valuĂ©es. Un seul bloc s'exĂ©cute, peu importe le nombre de elif. Python a donc exĂ©cutĂ© uniquement le bloc associĂ© Ă score >= 90.
| Situation | Utiliser |
|---|---|
| Les cas sont mutuellement exclusifs (un seul doit s'exécuter) | if / elif / else |
| Les vérifications sont indépendantes les unes des autres | Plusieurs if séparés |
Exemple oĂč plusieurs if sĂ©parĂ©s sont appropriĂ©s :
ph = 3.5
temperature_celsius = 85
pression_atm = 1.8
if ph < 6 :
print("â ïž Solution acide : portez des gants de protection.") # â
Exécuté
if temperature_celsius > 60 :
print("đĄïž TempĂ©rature Ă©levĂ©e : risque de brĂ»lure.") # â
Exécuté
if pression_atm > 1.5 :
print("đš Pression Ă©levĂ©e : vĂ©rifiez l'Ă©tanchĂ©itĂ© du systĂšme.") # â
Exécuté
Ici, les 3 avertissements sont complémentaires et ont du sens ensemble. Plusieurs if indépendants sont donc le bon choix.
Pour récapituler, la structure d'une instruction conditionnelle en Python est la suivante :
if: Obligatoire pour commencer une instruction conditionnelle.elif: Les blocselifsont optionnels.- Il peut y en avoir 0, 1, 2 ou plus.
- Chaque
elifvérifie une condition, seulement si toutes les conditions précédentes sontFalse.
else: Le blocelseest optionnel.- Il ne peut y avoir quâun seul
else. - Il est exécuté si toutes les conditions précédentes sont
False. - Le bloc
elsene prend pas de condition.
- Il ne peut y avoir quâun seul
- Indentation : le code Ă exĂ©cuter conditionnellement doit ĂȘtre indentĂ© sous l'instruction correspondante.
- Ordre des conditions :
- les conditions sont évaluées de haut en bas;
- la premiĂšre condition
Truedéclenche l'exécution du bloc de code correspondant; - dans une structure
if/elif/else, les autres conditions sont ignorĂ©es dĂšs quâune condition estTrue.
Les explications de cette section étaient-elles claires ?
Il est tout à fait possible d'écrire une structure conditionnelle à l'intérieur d'une autre.
On appelle cela des structures imbriquées (nested en anglais).
C'est utile quand une décision dépend d'une autre, comme dans la vraie vie!
Imaginons qu'on veuille classer un échantillon selon son pH ET sa température :
ph = 4.2
temperature_celsius = 75
if ph < 7 :
print("Solution acide.")
if temperature_celsius > 60 : # Condition imbriquée dans le if
print("â ïž Acide ET chaude : danger!")
else :
print("Acide mais à température normale.")
else :
print("Solution neutre ou basique.")
if temperature_celsius > 60 : # Condition imbriquée dans le else
print("â ïž Solution chaude : manipuler avec prĂ©caution.")
else :
print("Conditions stables.")
Résultat affiché avec ph = 4.2 et temperature_celsius = 75 :
Solution acide.
â ïž Acide ET chaude : danger!
đ Python entre d'abord dans le bloc if ph < 7, puis Ă©value la condition sur la tempĂ©rature seulement Ă l'intĂ©rieur de ce bloc.
Chaque niveau d'imbrication ajoute un niveau d'indentation supplémentaire.
C'est ce qui permet Ă Python de savoir Ă quel bloc appartient chaque instruction.
if condition_1 :
# Bloc de la condition 1 (indenté 1 fois)
if condition_2 :
# Bloc de la condition 2 (indenté 2 fois)
faire_quelque_chose()
else :
# Bloc else de la condition 2 (indenté 2 fois)
faire_autre_chose()
else :
# Bloc else de la condition 1 (indenté 1 fois)
faire_encore_autre_chose()
En astronomie, on peut classer une étoile selon sa luminosité et sa température de surface :
luminosite = 500 # En unités solaires
temperature_K = 8000 # En kelvins
if luminosite >= 100 :
print("Ătoile trĂšs lumineuse.")
if temperature_K >= 10000 :
print("â Classification : Ă©toile bleue gĂ©ante.")
elif temperature_K >= 6000 :
print("â Classification : Ă©toile blanche gĂ©ante.")
else :
print("â Classification : supergĂ©ante froide.")
elif luminosite >= 1 :
print("Ătoile de luminositĂ© moyenne.")
if temperature_K >= 6000 :
print("â Classification : Ă©toile de la sĂ©quence principale (type solaire ou plus chaud).")
else :
print("â Classification : Ă©toile naine froide.")
else :
print("Ătoile peu lumineuse.")
if temperature_K >= 4000 :
print("â Classification : naine blanche.")
else :
print("â Classification : naine brune.")
Résultat affiché avec luminosite = 500 et temperature_K = 8000 :
Ătoile trĂšs lumineuse.
â Classification : Ă©toile blanche gĂ©ante.
đ Le premier if/elif/else traite la luminositĂ©, puis, Ă l'intĂ©rieur de chacun de ses blocs, un second if/elif/else affine la classification selon la tempĂ©rature.
Plus on imbrique de niveaux, plus le code devient difficile à lire et à déboguer.
En général, une bonne rÚgle de base est de ne pas dépasser 2 à 3 niveaux.
Si vous vous retrouvez avec plus de 3 niveaux, c'est souvent le signe que le code pourrait ĂȘtre rĂ©organisĂ©, par exemple en utilisant des fonctions.
# â Difficile Ă lire â trop de niveaux d'imbrication
if condition_1 :
if condition_2 :
if condition_3 :
if condition_4 :
faire_quelque_chose() # On s'y perd!
# â
Plus lisible â on peut souvent combiner les conditions avec and
if condition_1 and condition_2 and condition_3 and condition_4 :
faire_quelque_chose()
| Situation | Approche recommandée |
|---|---|
| La 2e condition ne s'évalue que si la 1re est vraie | Imbrication |
| Les conditions sont indépendantes les unes des autres | Plusieurs if séparés |
| Les conditions peuvent ĂȘtre combinĂ©es simplement | and / or dans un seul if |
đ L'imbrication est le bon choix quand la logique est hiĂ©rarchique : on vĂ©rifie d'abord une catĂ©gorie gĂ©nĂ©rale, puis on affine Ă l'intĂ©rieur de cette catĂ©gorie.
Les explications de cette section étaient-elles claires ?
En programmation, on suit souvent le principe DRY (Don't Repeat Yourself).
Si vous remarquez que vous Ă©crivez la mĂȘme instruction plusieurs fois dans des blocs diffĂ©rents, c'est le signe qu'elle n'est pas vraiment conditionnelle!
Si une instruction se retrouve à la fois dans le if et dans le else, elle s'exécuterait dans tous les cas de toute façon.
Elle devrait donc ĂȘtre placĂ©e en dehors du bloc conditionnel â soit avant, soit aprĂšs, selon sa position dans les blocs de code.
Repérez l'instruction répétée inutilement dans les deux blocs :
# Version redondante
temperature = 37.8
if temperature > 37.5 :
print("Initialisation du protocole de mesure...") # â RĂ©pĂ©tĂ© au dĂ©but des 2 blocs!
print("â ïž FiĂšvre dĂ©tectĂ©e : consulter un mĂ©decin.")
else :
print("Initialisation du protocole de mesure...") # â RĂ©pĂ©tĂ© au dĂ©but des 2 blocs!
print("â
Température normale.")
Peu importe la valeur de temperature, l'initialisation du protocole est toujours affichée.
La répéter dans les deux blocs est inutile et rend le code plus difficile à maintenir.
# Version sans redondance
temperature = 37.8
print("Initialisation du protocole de mesure...") # â
Exécuté dans tous les cas avant les 2 blocs
if temperature > 37.5 :
print("â ïž FiĂšvre dĂ©tectĂ©e : consulter un mĂ©decin.")
else :
print("â
Température normale.")
Le code est plus court, plus lisible, et plus facile Ă modifier : si le message d'initialisation change, on n'a qu'un seul endroit Ă modifier.
MĂȘme problĂšme, mais cette fois l'instruction rĂ©pĂ©tĂ©e se trouve Ă la fin de chaque bloc :
# Version redondante
masse_g = 5.2
volume_mL = 10.0
if masse_g > 0 and volume_mL > 0 :
densite = masse_g / volume_mL
print(f"Densité calculée : {densite} g/mL")
print("--- Fin de l'analyse ---") # â RĂ©pĂ©tĂ© Ă la fin des 2 blocs!
else :
print("â ïž ParamĂštres invalides, calcul impossible.")
print("--- Fin de l'analyse ---") # â RĂ©pĂ©tĂ© Ă la fin des 2 blocs!
# Version sans redondance
masse_g = 5.2
volume_mL = 10.0
if masse_g > 0 and volume_mL > 0 :
densite = masse_g / volume_mL
print(f"Densité calculée : {densite} g/mL")
else :
print("â ïž ParamĂštres invalides, calcul impossible.")
print("--- Fin de l'analyse ---") # â
Exécuté dans tous les cas aprÚs les 2 blocs
| Position de la redondance | Solution |
|---|---|
| Au début de chaque bloc | Placer l'instruction avant le bloc if |
| Ă la fin de chaque bloc | Placer l'instruction aprĂšs le bloc if/else |
| Au d ébut et à la fin | Placer une instruction avant et une aprÚs |
đ La rĂšgle est simple : si une instruction s'exĂ©cute dans tous les cas, elle ne devrait jamais se retrouver Ă l'intĂ©rieur d'un if ou d'un else.
# Version redondante
pression_atm = 2.3
if pression_atm > 2.0 :
print("=== Rapport de pression ===") # â DĂ©but redondant
print("â ïž Pression critique dĂ©tectĂ©e!")
print("=== Fin du rapport ===") # â Fin redondante
else :
print("=== Rapport de pression ===") # â DĂ©but redondant
print("â
Pression dans les normes.")
print("=== Fin du rapport ===") # â Fin redondante
# Version sans redondance
pression_atm = 2.3
print("=== Rapport de pression ===") # â
Redondance déplacée avant les blocs
if pression_atm > 2.0 :
print("â ïž Pression critique dĂ©tectĂ©e!")
else :
print("â
Pression dans les normes.")
print("=== Fin du rapport ===") # â
Redondance déplacée aprÚs les blocs
Le résultat affiché est identique, mais la version propre est bien plus facile à lire et à maintenir!
Parfois, deux instructions se ressemblent mais ne sont pas identiques : elles ne peuvent donc pas ĂȘtre sorties du bloc.
# â
Ce n'est PAS de la redondance, car les messages sont différents!
ph = 4.2
if ph < 7 :
print(f"Le pH de {ph} indique une solution acide.")
else :
print(f"Le pH de {ph} indique une solution basique ou neutre.")
Ici, les deux print contiennent du texte différent. Ils doivent rester dans leurs blocs respectifs.
Les explications de cette section étaient-elles claires ?
Pour les instructions conditionnelles simples, on peut utiliser une forme compacte en une seule ligne.
Par exemple :
age = 20
print("Vous ĂȘtes majeur.") if age >= 18 else print("Vous ĂȘtes mineur.")
On peut aussi utiliser cette forme compacte pour stocker le résultat dans une variable :
age = 20
statut = "majeur" if age >= 18 else "mineur"
print(statut) # Affiche "majeur"
La forme compacte est utile pour des conditions simples et des actions courtes.
Cependant, pour des conditions plus complexes ou des blocs de code plus longs,
il est préférable d'utiliser la forme standard avec indentation pour une meilleure lisibilité.
On peut aussi utiliser des elif dans une forme compacte, mais cela peut rapidement devenir difficile Ă lire.
Par exemple :
score = 85
resultat = "Excellent" if score >= 90 else "Bien" if score >= 75 else "Passable" if score >= 50 else "Ăchec"
print(resultat) # Affiche "Bien"
Si on a besoin de elif, il est préférable d'utiliser la forme standard pour une meilleure lisibilité.
Les explications de cette section étaient-elles claires ?
Quand on écrit une fonction, il faut s'assurer que les entrées (paramÚtres) ont du sens.
Sinon, on risque d'obtenir des résultats absurdes ou des erreurs difficiles à comprendre.
Comparez ces deux versions :
# Version 1 â sans validation
def densite(masse, volume):
return masse / volume
print(densite(10, 2)) # â
5.0
print(densite(-3, 5)) # â ïž -0.6 g/mL sans avertissement (rĂ©sultat absurde), le programme continue malgrĂ© tout!
print(densite(8, 0)) # â Erreur Python brute (ZeroDivisionError), le programme arrĂȘte ici!
a = 1 + 2 # Cette instruction ne sera jamais exécutée.
# Version 2 â avec validation
def densite(masse, volume):
if masse < 0:
raise ValueError("La masse doit ĂȘtre positive.")
if volume <= 0:
raise ValueError("Le volume doit ĂȘtre supĂ©rieur Ă 0.")
return masse / volume
print(densite(10, 2)) # â
5.0
print(densite(-3, 5)) # â ValueError : La masse doit ĂȘtre positive, message clair, le programme arrĂȘte ici!
print(densite(8, 0)) # Cette instruction et les suivantes ne seront jamais exécutées.
a = 1 + 2
đ La version 2 donne des messages d'erreur explicites, Ă©vite les rĂ©sultats absurdes et rend le code plus robuste et rĂ©utilisable.
raise â mettre une barriĂšre dans une fonctionraise permet de provoquer volontairement une erreur si une condition n'est pas respectĂ©e.
C'est la façon de signaler au programmeur qui appelle la fonction qu'il l'utilise avec de mauvaises valeurs.
def concentration(masse_g, volume_L):
if masse_g < 0:
raise ValueError("La masse doit ĂȘtre positive.")
if volume_L <= 0:
raise ValueError("Le volume doit ĂȘtre supĂ©rieur Ă 0.")
return masse_g / volume_L
DÚs qu'une condition invalide est détectée, Python interrompt immédiatement la fonction et remonte l'erreur à l'appelant.
Les lignes suivantes à l'intérieur de la fonction ne sont jamais exécutées (comme c'est le cas avec l'instruction return).
try/except â mettre un filet de sĂ©curitĂ© Ă l'appeltry/except permet de rattraper une erreur qui se produit, plutĂŽt que de laisser le programme planter.
Exécutez ce code sans try/except, observez l'erreur, puis ajoutez le filet et relancez :
# Sans filet : le programme plante
print(concentration(4, 20)) # â
OK
print(concentration(-10, 20)) # â Le programme s'arrĂȘte ici avec une erreur brute
print(concentration(4, 5)) # Jamais atteint
# Avec filet : le programme gĂšre l'erreur proprement
try:
print(concentration(4, 20)) # â
Exécuté normalement
print(concentration(-10, 20)) # â LĂšve ValueError â on saute au except
print(concentration(4, 5)) # âïž Jamais atteint (on est dĂ©jĂ dans le except)
except ValueError as e:
print(f"Une erreur est survenue : {e}")
La variable e contient le message d'erreur personnalisé passé à raise.
On peut choisir de faire ce qu'on veut du message :
- l'afficher Ă la console
- le journaliser dans un fichier
- exécuter un bout de code en particulier en fonction du message
raise et try/except| MĂ©canisme | RĂŽle | OĂč l'Ă©crire |
|---|---|---|
| raise | Signaler un problĂšme (mettre une barriĂšre) | Dans la fonction, lĂ oĂč les paramĂštres sont vĂ©rifiĂ©s |
| try/except | Attraper un problĂšme (mettre un filet) | Ă l'appel de la fonction, pour gĂ©rer proprement les erreurs et Ă©viter l'arrĂȘt du programme |
đ On utilise raise pour protĂ©ger la fonction, et try/except pour que l'appelant dĂ©cide quoi faire en cas d'erreur.
Ce n'est pas seulement votre code qui peut lever des exceptions â les fonctions de la bibliothĂšque standard de Python le font aussi.
Comprendre quelles erreurs elles peuvent produire vous aide Ă les anticiper et mĂȘme les intercepter (avec un bloc try/except) pour Ă©viter l'arrĂȘt pur et simple du programme.
math â erreurs de domaine mathĂ©matique
import math
math.sqrt(25) # â
5.0
math.sqrt(-1) # â ValueError: math domain error (racine d'un nombre nĂ©gatif)
math.log(100) # â
4.605...
math.log(0) # â ValueError: math domain error (log(0) est indĂ©fini)
math.log(-5) # â ValueError: math domain error (log d'un nĂ©gatif)
math.factorial(5) # â
120
math.factorial(-1)# â ValueError: factorial() not defined for negative values
math.factorial(2.5)# â TypeError: 'float' object cannot be interpreted as an integer
đ Le module math lĂšve une ValueError dĂšs qu'on sort du domaine mathĂ©matique valide (valeur impossible Ă calculer).
int() et float() â erreurs de conversion
int("42") # â
42
int("3.14") # â ValueError: invalid literal for int() with base 10: '3.14'
int("abc") # â ValueError: invalid literal for int() with base 10: 'abc'
float("3.14") # â
3.14
float("abc") # â ValueError: could not convert string to float: 'abc'
đ int() et float() lĂšvent une ValueError si la chaĂźne de caractĂšres ne reprĂ©sente pas un nombre valide.
C'est une erreur trÚs fréquente quand on lit une saisie utilisateur ou des données provenant d'un fichier.
Intercepter ces erreurs avec try/except
Voici un exemple concret qui combine math et la conversion :
import math
def calculer_racine(valeur_texte):
try:
nombre = float(valeur_texte) # Peut lever ValueError si non numérique
resultat = math.sqrt(nombre) # Peut lever ValueError si nombre < 0
return resultat
except ValueError as e:
print(f"Erreur : {e}")
return None
#Toutes les instructions ci-dessous sont exécutées!
print(calculer_racine("25")) # â
5.0
print(calculer_racine("-4")) # â
La fonction gĂšre l'erreur pour Ă©viter l'arrĂȘt du programme et elle retourne None
print(calculer_racine("abc")) # â
La fonction gĂšre l'erreur pour Ă©viter l'arrĂȘt du programme et elle retourne None
a = 1 + 2 # Cette instruction est finalement exécutée!
đ Un seul bloc try/except attrape Ă la fois les erreurs de conversion et les erreurs de domaine, car les deux lĂšvent une ValueError.
L'appel de la fonction calculer_racine() ne causera jamais l'arrĂȘt du programme car les erreurs sont bien attrapĂ©es.
La fonction va soit retourner :
- soit une valeur valide
- soit la valeur None
Bonne pratique : lire la documentation avant d'utiliser une fonction
Les exemples ci-dessus ne sont pas une liste exhaustive â chaque fonction de Python peut avoir son propre comportement en cas d'erreur.
Avant d'utiliser une fonction inconnue, consultez sa documentation pour savoir quelles exceptions elle peut lever et dans quelles circonstances.
Par exemple, la page de documentation de math.sqrt indique explicitement qu'une ValueError est levĂ©e si l'argument est nĂ©gatif. C'est cette information qui vous permet d'Ă©crire un try/except adaptĂ© â ni trop large (attraper des erreurs imprĂ©vues), ni trop Ă©troit (manquer un cas rĂ©el).
Quand vous intégrez une nouvelle fonction dans votre code, posez-vous toujours la question :
"Qu'est-ce qui pourrait mal se passer ici, et est-ce que ma fonction le gĂšre?"
isinstance)Pour une validation solide, on peut aussi vĂ©rifier que les paramĂštres sont du bon type avant mĂȘme de vĂ©rifier leur valeur.
def calculer_concentration(masse_g, volume_L):
if not isinstance(masse_g, (int, float)):
raise TypeError("La masse doit ĂȘtre un nombre (int ou float).")
if not isinstance(volume_L, (int, float)):
raise TypeError("Le volume doit ĂȘtre un nombre (int ou float).")
if masse_g < 0:
raise ValueError("La masse doit ĂȘtre positive.")
if volume_L <= 0:
raise ValueError("Le volume doit ĂȘtre supĂ©rieur Ă 0.")
return masse_g / volume_L
try:
print(calculer_concentration(10, 2)) # â
5.0
print(calculer_concentration(-5, 2)) # â LĂšve ValueError â on saute au except
print(calculer_concentration(10, 0)) # âïž Jamais atteint (on est dĂ©jĂ dans le except)
print(calculer_concentration(10, "a")) # âïž Jamais atteint (on est dĂ©jĂ dans le except)
except (TypeError, ValueError) as e:
print(f"Erreur : {e}")
La fonction isinstance(valeur, type) retourne True si la valeur est du type donné.
Par exemple : isinstance(5, int) â True, isinstance("5", int) â False.
On peut tester plusieurs types Ă la fois : isinstance(5, (int, float)) â True.
đ Remarquez l'ordre des vĂ©rifications : on valide d'abord les types, puis les valeurs. C'est important, car une valeur du mauvais type (comme une masse de type str) ne pourrait mĂȘme pas ĂȘtre comparĂ©e Ă 0 sans provoquer une erreur.
Nous nous limitons aux trois exceptions les plus courantes :
| Exception | Quand l'utiliser |
|---|---|
| ZeroDivisionError | Une division par zéro est tentée ou le dénominateur est nul |
| TypeError | Le type de la valeur transmise n'est pas celui attendu |
| ValueError | La valeur est du bon type mais ne respecte pas les contraintes (ex. : masse négative) |
- N'attrapez avec
exceptque les erreurs prĂ©vues â sinon on risque de cacher de vrais bogues. - Donnez toujours un message utile dans
raisepour que l'erreur soit facile Ă comprendre. - Validez d'abord le type, puis la valeur : une masse de type
strne peut mĂȘme pas ĂȘtre comparĂ©e Ă 0. - L'ordre des validations dans la fonction a de l'importance : vĂ©rifiez ce qui est le plus fondamental en premier.
Avant de retourner un résultat, votre fonction a-t-elle vérifié :
- â
Les types sont corrects (
int,float, etc.) ? - â Les domaines sont respectĂ©s (positif, non nul, dans un intervalle, etc.) ?
- â Les cas limites sont couverts (valeur nulle, nĂ©gative, vide, etc.) ?
Les explications de cette section étaient-elles claires ?
đ”ïžââïž Trace dâexĂ©cution avec des structures conditionellesâ
Voici un exemple de trace d'exécution contenant des structures conditionnelles
- Certaines lignes ne s'exécutent pas, c'est le principe de la condition!
- On indique les lignes qui testent une condition :
if,elif,match,case(mais paselsenicase _).
Codeâ
Si on a le code suivant :
a = 42
if a > 100:
print('a est grand')
elif a > 10:
print('a est moyen')
elif a > 1:
print('a est petit')
else:
print('a est trĂšs petit')
print('a est nul') if a == 0 else print('fin')
Traceâ
On aura la trace suivante :
| portée globale | |||||
|---|---|---|---|---|---|
| #ligne | a | affichage | pile d'appels | fonction appelée | valeur retournée |
| 1 | 42 | ||||
| 2 | 42 | ||||
| 4 | 42 | ||||
| 5 | 42 | a est moyen | |||
| 11 | 42 | fin | |||
Codeâ
Si on a le code suivant :
a = 42
match a:
case 6:
print('a est égal à 6')
case 7:
print('a est égal à 7')
case 42:
print('a est égal à 42')
case 420:
print('a est égal à 420')
case _:
print("a n'est pas 6, 7, 42 ou 420")
Traceâ
On aura la trace suivante :
| portée globale | |||||
|---|---|---|---|---|---|
| #ligne | a | affichage | pile d'appels | fonction appelée | valeur retournée |
| 1 | 42 | ||||
| 2 | 42 | ||||
| 3 | 42 | ||||
| 5 | 42 | ||||
| 7 | 42 | ||||
| 8 | 42 | a est égal à 42 | |||
Pour favoriser une progression efficace, ce cours adopte une approche de classe inversée. Ce modÚle déplace l'acquisition théorique hors de la classe pour transformer les heures de rencontre en véritables séances d'application pratique.
-
Ă la maison (Exploration et Appropriation) : Vous ĂȘtes le maĂźtre de votre rythme. Ces activitĂ©s vous permettent de dĂ©couvrir les nouveaux concepts et tester les exemples au moment oĂč vous ĂȘtes le plus concentrĂ©. Si une notion vous semble obscure, n'hĂ©sitez pas Ă poser des questions Ă votre prof au fur et Ă mesure.
-
En classe (Application et Consolidation) : Le temps en prĂ©sentiel est une ressource prĂ©cieuse. Nous l'utilisons pour nous attaquer aux dĂ©fis plus complexes et aux exercices de programmation qui demandent une mobilisation active de vos connaissances. Câest le moment idĂ©al pour obtenir une rĂ©troaction immĂ©diate, collaborer avec vos pairs et bĂ©nĂ©ficier de l'accompagnement de votre enseignant au moment oĂč vous en avez le plus besoin.
- đ ActivitĂ©s Ă faire Ă la maison
- đ« ActivitĂ©s Ă faire en classe
đ§ Auto-validation des connaissancesâ
Ce formulaire sert à vérifier votre compréhension des éléments les plus importants de la rencontre R04. Ne faites ce questionnaire que lorsque vous vous sentez en trÚs bonne maßtrise de la matiÚre. En classe, dÚs votre arrivée, vous aurez un questionnaire trÚs similaire, évalué sommativement, à compléter sans accÚs à aucune documentation.
Ne pas remplir le formulaire diminue fortement vos chances de rĂ©ussir lâĂ©valuation sommative en dĂ©but de rencontre.
Assurez-vous de bien comprendre toutes les notions derriĂšre chaque question.