2.11. Conditionnelles¶
Une conditionnelle n’exécute un bloc de code que lorsqu’un certain test est évalué à vrai. Le mot-clé est if, éventuellement suivi d’une ou plusieurs branches elif (« else if ») et d’un else final.
n = 42
if n > 0:
print("positive")
elif n < 0:
print("negative")
else:
print("zero")
Le corps de chaque branche est tout ce qui est indenté en dessous (quatre espaces par convention). Python parcourt les branches dans l’ordre, exécute la première dont le test est vrai, et ignore les autres. Le bloc else ne s’exécute que si tous les tests précédents étaient faux ; il est toujours optionnel.
Une seule branche s’exécute jamais. Les tests sont évalués de haut en bas jusqu’à ce que l’un réussisse ; les autres sont ignorés.¶
2.11.1. Valeur de vérité¶
Un test dans un if n’a pas à renvoyer True ou False – toute valeur compte comme vraie (truthy) ou fausse (falsy). Les valeurs fausses sont :
Tout le reste est vrai. Cela vous permet d’écrire des tests compacts :
if name: # false on empty string
print("hello", name)
if items: # false on empty list, dict, etc.
process(items)
Sachez que la valeur de vérité change le sens. if value: n’est pas identique à if value is not None: – la première est également fausse lorsque value vaut 0 ou "". Lorsque vous voulez réellement dire « est-ce exactement None », utilisez explicitement is None / is not None.
2.11.2. Expressions ternaires¶
Une conditionnelle peut apparaître à l’intérieur d’une expression :
label = "even" if n % 2 == 0 else "odd"
À lire comme « label vaut "even" si n % 2 == 0 sinon "odd" ». Pratique pour les expressions en une ligne ; pour tout ce qui dépasse une ligne, une instruction if complète est plus facile à lire.
2.11.3. Imbrication et retours anticipés¶
Les conditionnelles peuvent s’imbriquer à une profondeur arbitraire, mais chaque niveau d’indentation supplémentaire rend une fonction plus difficile à lire. L’exemple ci-dessous vérifie quatre conditions avant d’effectuer le vrai travail et laisse la ligne utile enfouie quatre indentations plus loin :
def process(item):
if item is not None:
if item.is_valid():
if item.size() > 0:
if item.owner == "me":
return do_the_work(item)
return None
Deux schémas permettent d’aplatir ce genre de code.
2.11.3.1. Retours anticipés pour les gardes¶
Traitez d’abord chaque cas d”« abandon », chacun avec son propre return, afin que la logique principale reste au niveau d’indentation extérieur. Chaque garde se lit comme « ce n’est pas un cas que nous traitons ; on sort » :
def process(item):
if item is None:
return None
if not item.is_valid():
return None
if item.size() == 0:
return None
if item.owner != "me":
return None
return do_the_work(item)
Le « chemin principal » est désormais une seule ligne au bas de la fonction, et non enfoui dans quatre niveaux. Ce style est parfois appelé schéma des clauses de garde (guard clause).
2.11.3.2. Combiner des tests avec and / or¶
Lorsque plusieurs conditions doivent toutes être vraies pour une même branche, combinez-les avec and plutôt que de les imbriquer. Les conditions qui déclenchent chacune indépendamment la branche se combinent avec or :
# all must hold -- use `and`
if user.is_admin() and user.has_permission("write") and not locked:
save()
# any one of them is enough -- use `or`
if c == " " or c == "\t" or c == "\n":
whitespace_count += 1
Les deux formes évaluent en court-circuit, de sorte qu’une vérification coûteuse à droite ne s’exécute que lorsque les vérifications moins coûteuses à gauche n’ont pas déjà tranché la question.