En Python, and et
or appliquent la logique booléenne comme vous
pourriez l’attendre, mais ils ne retournent pas de valeurs booléennes,
ils retournent une des valeurs comparées.
Lorsqu’on utilise and les valeurs sont
évaluées dans un contexte booléen de gauche à droite.
0, '',
[], (),
{} et None valent faux dans
ce contexte, tout le reste vaut vrai.[1]Si toutes les valeurs valent vrai dans un contexte
booléen, and retourne la dernière valeur. Ici
and évalue 'a', qui vaut
vrai, puis 'b', qui vaut vrai et retourne
'b'.
Si une des valeurs vaut faux and
retourne la première valeur fausse. Ici '' est
la première valeur fausse.
Toutes les valeurs sont vrai, donc and
retourne la dernière valeur, 'c'.
Lorsqu’on utilise or, les valeurs sont
évaluées dans un contexte booléen de gauche à droite, comme pour
and. Si une des valeurs vaut vrai,
or la retourne immédiatement. Dans ce cas
'a' est la première valeur vraie.
or évalue '', qui vaut
faux, puis 'b', qui vaut vrai et retourne
'b'.
Si toutes les valeurs valent faux, or
retourne la dernière valeur. or évalue
'', qui vaut faux, puis [],
qui vaut faux, puis {}, qui vaut faux et
retourne {}.
Notez que or continue l’évaluation
seulement jusqu’à ce qu’il trouve une valeur vraie, le reste est
ignoré. C’est important si certaines valeurs peuvent avoir un
effet de bord. Ici, la fonction sidefx n’est
jamais appelée, car or évalue
'a', qui vaut vrai et retourne
'a' immédiatement.
Si vous êtes un programmeur
C, vous êtes certainement
familier de l’expression ternaire
bool ? a :
b, qui s’évalue à a si
bool vaut vrai et à b
dans le cas contraire. Le fonctionnement de and et
or en Python vous permet
d’accomplir la même chose.
4.6.1. Utilisation de l'astuce and-or
Exemple 4.17. Présentation de l’astuce and-or
>>> a = "first">>> b = "second">>> 1 and a or b'first'>>> 0 and a or b'second'
Cette syntaxe ressemble à celle de l’expression ternaire
bool ? a :
b de
C. L’expression est
évaluée de gauche à droite, donc le and est
évalué en premier. 1 and 'first' s’évalue à
'first', puis 'first' or
'second' s’évalue à 'first'.
0 and 'first' s’évalue à
0, puis 0 or 'second'
s’évalue à 'second'.
Cependant, puisque cette expression en
Python est simplement de la logique booléenne
et non un dispositif spécial du langage, il y a une différence très,
très importante entre l’astuce and-or en
Python et la syntaxe
bool ? a :
b en
C. Si a
vaut faux, l’expression ne fonctionnera pas comme vous vous y attendez.
(Vous devinez que cela m’a déjà joué des tours. Et plus d’une fois
!)
Exemple 4.18. Quand l’astuce and-or échoue
>>> a = "">>> b = "second">>> 1 and a or b'second'
Puisque a est une chaîne vide, ce que
Python évalue à faux dans un contexte
booléen, 1 and '' s’évalue à
'', puis '' or 'second'
s’évalue à 'second'. Zut ! Ce n’est pas ce que
nous voulions.
L’astuce and-or,
bool and a or
b, ne fonctionne pas comme l’expression
ternaire de Cbool ? a :
b quand a s’évalue à
faux dans un contexte booléen.
La véritable astuce cachée derrière l’astuce
and-or, c’est de s’assurer que
a ne vaut jamais faux. Une manière habituelle de le
faire est de changer a en
[a] et b en
[b] et de prendre le premier
élément de la liste retournée, qui sera soit a soit
b.
Exemple 4.19. L’astuce and-or en toute sécurité
>>> a = "">>> b = "second">>> (1 and [a] or [b])[0]''
Puisque [a] est une
liste non-vide, il ne vaut jamais faux. Même si
a est 0 ou
'' ou une autre valeur fausse, la liste
[a] vaut vrai puisqu’elle a
un élément.
On peut penser que cette astuce apporte plus de complication que
d’avantages. Après tout, on peut obtenir le même résultat avec une
instruction if, alors pourquoi s’embarasser de tout
ces problèmes ? Mais dans de nombreux cas, le choix se fait entre deux
valeurs constantes et donc vous pouvez utiliser cette syntaxe plus
simple sans vous inquiéter puisque vous savez que a
vaudra toujours vrai. Et même si vous devez utiliser la version sûre
plus complexe, il y a parfois de bonnes raisons de le faire, il y a des
cas en Python où les instructions
if ne sont pas autorisées, comme dans les fonctions
lambda.
[1] Presque tout, en fait. Par défaut, les instances de
classes valent vrai dans un contexte booléen mais vous pouvez
définir des méthodes spéciales de votre classe pour faire
qu’une instance vale faux. Vous apprendrez tout sur les
classes et les méthodes spéciales au Chapitre 5.