Mettre une instruction if-elif-else sur une seule ligne?

125

J'ai lu les liens ci-dessous, mais cela ne répond pas à ma question.
Python a-t-il un opérateur conditionnel ternaire? (la question est de condenser l'instruction if-else sur une ligne)

Existe-t-il un moyen plus simple d'écrire une instruction if-elif-else pour qu'elle tienne sur une seule ligne?
Par exemple,

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

Ou un exemple réel:

if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

Je pense juste que si l'exemple ci-dessus pouvait être écrit de la manière suivante, cela pourrait paraître plus concis.

x=2 if i>100 elif i<100 1 else 0 [WRONG]
Matt Elson
la source

Réponses:

187

Non, ce n'est pas possible (du moins pas avec des déclarations arbitraires), ni souhaitable. Tout mettre sur une seule ligne violerait très probablement PEP-8 où il est obligatoire que les lignes ne dépassent pas 80 caractères.

C'est aussi contre le Zen de Python: "La lisibilité compte". (Tapez import thisà l'invite Python pour lire le tout).

Vous pouvez utiliser une expression ternaire en Python, mais uniquement pour les expressions, pas pour les instructions:

>>> a = "Hello" if foo() else "Goodbye"

Éditer:

Votre question révisée montre maintenant que les trois énoncés sont identiques à l'exception de la valeur attribuée. Dans ce cas, un opérateur ternaire chaîné fonctionne, mais je pense toujours qu'il est moins lisible:

>>> i=100
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
0
>>> i=101
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
2
>>> i=99
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
1
Tim Pietzcker
la source
Pourquoi la deuxième expression n'a-t-elle pas retourné 0? Je suis au -dessus de 100
AstralWolf
6
@AstralWolf: Merci beaucoup! Cela illustre parfaitement le point que j'essayais de faire valoir - une expression ternaire enchaînée est possible mais moins lisible et évidemment facile à mal comprendre.
Tim Pietzcker
1
Si vous en avez besoin pour être plus lisible, vous pouvez mettre des crochets autour, comme ceci: a = 1 if i < 100 else (2 if i > 100 else 0)(Non testé, mais je pense que cela devrait fonctionner)
Zac
@TimPietzcker comment décririez-vous la différence entre les expressions et les déclarations?
AsheKetchum
63

Si vous n'avez besoin que de différentes expressions pour différents cas, cela peut fonctionner pour vous:

expr1 if condition1 else expr2 if condition2 else expr

Par exemple:

a = "neg" if b<0 else "pos" if b>0 else "zero"
Lycha
la source
1
"pos"n'est pas une déclaration, c'est une expression.
Tim Pietzcker
@TimPietzcker Merci, j'ai mis à jour le message pour être plus précis.
Lycha
20

Imbriquez simplement une autre clause if dans l'instruction else. Mais cela ne le rend pas plus joli.

>>> x=5
>>> x if x>0 else ("zero" if x==0 else "invalid value")
5
>>> x = 0
>>> x if x>0 else ("zero" if x==0 else "invalid value")
'zero'
>>> x = -1
>>> x if x>0 else ("zero" if x==0 else "invalid value")
'invalid value'
David Lai
la source
1
Pour moi, c'est beaucoup plus lisible que la réponse acceptée car elle maintient la structure et le concept de la première clause; juste matière subjective.
Ezarate11
12

Malgré quelques autres réponses: OUI c'est possible :

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

se traduit par la doublure suivante:

statement1 if expression1 else (statement2 if expression2 else statement3)

en fait, vous pouvez les imbriquer jusqu'à l'infini. Prendre plaisir ;)

Gustavz
la source
qu'en est-il du temps pris? ce que je suppose, ces muti-boucles prendront beaucoup plus de temps. il peut donc y avoir une alternative aux boucles imbriquées, pour une meilleure vitesse de consommation.
loveR
salut @loveR, ce n'est pas une boucle, c'est juste une instruction if else imbriquée, et par conséquent de temps négligeable
gustavz
7

Vous pouvez éventuellement utiliser la getméthode d'un dict:

x = {i<100: -1, -10<=i<=10: 0, i>100: 1}.get(True, 2)

Vous n'avez pas besoin de la getméthode s'il est garanti que l'une des clés est évaluée comme suit True:

x = {i<0: -1, i==0: 0, i>0: 1}[True]

Au plus une des clés devrait idéalement être évaluée True. Si plus d'une clé est évaluée True, les résultats peuvent sembler imprévisibles.

Shane
la source
4
if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

Si vous souhaitez utiliser le code mentionné ci-dessus sur une seule ligne, vous pouvez utiliser ce qui suit:

x = 2 if i > 100 else 1 if i < 100 else 0

Ce faisant, x se verra attribuer 2 si i> 100, 1 si i <100 et 0 si i = 100

Roshanpoudel
la source
3

Cela dépend également de la nature de vos expressions. Le conseil général sur les autres réponses «ne pas le faire» est tout à fait valable pour les déclarations génériques et les expressions génériques.

Mais si tout ce dont vous avez besoin est une table "dispatch", comme appeler une fonction différente selon la valeur d'une option donnée, vous pouvez placer les fonctions à appeler dans un dictionnaire.

Quelque chose comme:

def save(): 
   ...
def edit():
   ...
options = {"save": save, "edit": edit, "remove": lambda : "Not Implemented"}

option = get_input()
result = options[option]()

Au lieu d'un if-else:

if option=="save":
    save()
...
jsbueno
la source
2

Les gens ont déjà mentionné les expressions ternaires. Parfois, avec une simple affectation conditionnelle comme exemple, il est possible d'utiliser une expression mathématique pour effectuer l'affectation conditionnelle. Cela peut ne pas rendre votre code très lisible, mais il l'obtient sur une ligne assez courte. Votre exemple pourrait être écrit comme ceci:

x = 2*(i>100) | 1*(i<100)

Les comparaisons seraient vraies ou fausses, et lors de la multiplication avec des nombres, elles seraient alors 1 ou 0. On pourrait utiliser un + au lieu d'un | au milieu.

Ant6n
la source
1

L' opérateur ternaire est le meilleur moyen d'obtenir une expression concise. La syntaxe est variable = value_1 if condition else value_2. Donc, pour votre exemple, vous devez appliquer l'opérateur ternaire deux fois:

i = 23 # set any value for i
x = 2 if i > 100 else 1 if i < 100 else 0
Yoelvis
la source
0

Vous pouvez utiliser des instructions if ternaires imbriquées.

# if-else ternary construct
country_code = 'USA'
is_USA = True if country_code == 'USA' else False
print('is_USA:', is_USA)

# if-elif-else ternary construct
# Create function to avoid repeating code.
def get_age_category_name(age):
    age_category_name = 'Young' if age <= 40 else ('Middle Aged' if age > 40 and age <= 65 else 'Senior')
    return age_category_name

print(get_age_category_name(25))
print(get_age_category_name(50))
print(get_age_category_name(75))
k0L1081
la source