222

Is there an easier way of writing an if-elif-else statement so it fits on one line?
For example,

if expression1:
    statement1
elif expression2:
    statement2
else:
    statement3

Or a real-world example:

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

I just feel if the example above could be written the following way, it could look like more concise.

x = 2 if i>100 elif i<100 1 else 0   # [WRONG]

I have read the link below, but it doesn't address my question.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Matt Elson
  • 4,177
  • 8
  • 31
  • 46

14 Answers14

295

No, it's not possible (at least not with arbitrary statements), nor is it desirable. Fitting everything on one line would most likely violate PEP-8 where it is mandated that lines should not exceed 80 characters in length.

It's also against the Zen of Python: "Readability counts". (Type import this at the Python prompt to read the whole thing).

You can use a ternary expression in Python, but only for expressions, not for statements:

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

Edit:

Your revised question now shows that the three statements are identical except for the value being assigned. In that case, a chained ternary operator does work, but I still think that it's less readable:

>>> i = 100
>>> x = 2 if i>100 else 1 if i<100 else 0
>>> x
0
>>> i = 101
>>> x = 2 if i>100 else 1 if i<100 else 0
>>> x
2
>>> i = 99
>>> x = 2 if i>100 else 1 if i<100 else 0
>>> x
1
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 1
    Why didn't the second expression return 0? _i_ is above 100 – astralwolf Jan 03 '16 at 09:36
  • 11
    @AstralWolf: Thank you very much! This perfectly illustrates the point I was trying to make - a chained ternary expression is possible but less readable, and obviously easy to misunderstand. – Tim Pietzcker Jan 13 '16 at 09:20
  • 4
    If you need it to be more readable, you could put brackets around it, like this: `a = 1 if i < 100 else (2 if i > 100 else 0)` (Untested, but I think it should work) – Zac Sep 27 '16 at 16:48
  • @TimPietzcker how would you describe the difference between expressions and statements? – AsheKetchum Apr 27 '17 at 14:50
  • 1
    An expression has a value; a statement does not. – chepner Jan 19 '23 at 23:00
  • I just changed the order to match the OP, but now astralwolf's comment makes less sense. I think the equivalent now would be *"Why didn't the **third** expression return 0? i is **below** 100"* – wjandrea Aug 13 '23 at 17:46
114

If you only need different expressions for different cases then this may work for you:

expr1 if condition1 else expr2 if condition2 else expr

For example:

a = "neg" if b<0 else "pos" if b>0 else "zero"
Lycha
  • 9,937
  • 3
  • 38
  • 43
  • How about in a case where ```expr1``` is another if else? will it have a conflict with this one liner expression in the expected output? – Ice Bear Aug 08 '22 at 10:24
  • maybe it would be better if you change the `expr` to `expr3` – Benyamin Jafari Sep 16 '22 at 12:09
  • @IceBear You could wrap it in parentheses to avoid any conflict, but nested conditional expressions are hard to read, so you might want to revert back to separate lines. – wjandrea Aug 13 '23 at 18:03
61

Despite some other answers: YES it IS possible:

if expression1:
    statement1
elif expression2:
    statement2
else:
    statement3

translates to the following one liner:

statement1 if expression1 else (statement2 if expression2 else statement3)

in fact you can nest those till infinity. Enjoy ;)


UPDATE: This is how it looks for the "real-world" example:

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

translates to:

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

So my initial answer was not precise enough, but this solution works for what OP asks.

gustavz
  • 2,964
  • 3
  • 25
  • 47
  • how about the time taken? what I suppose, these muti-looping will be much more time consuming. so can there be an alternative to nested loops, for better speed of consuming. – loveR Jan 21 '20 at 10:50
  • 2
    hi @loveR, this is no loop, its just a nested if else statement, and therefor of negligible time – gustavz May 04 '20 at 09:21
  • **No it's not possible** with arbitrary statements, for example, this is invalid: `k += 1 if k_add else v += 1 if v_add else s += 0`. [Tim is right](/a/14029300/4518341), you can only use it with expressions, **not** statements. – wjandrea Aug 13 '23 at 17:56
  • you are right in that I can be a bit more precise in my answer, will update it for OP's real-world example. – gustavz Aug 17 '23 at 08:09
  • @wjandrea see my update for how a one-liner looks for OP's real-world example. So my answer is definitely correct in the sense of what OP asks for. – gustavz Aug 17 '23 at 08:16
30

Just nest another if clause in the else statement. But that doesn't make it look any prettier.

>>> 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
  • 814
  • 7
  • 13
  • 3
    For me, this is much more readable than the accepted answer because it maintains the structure and concept of the first clause; just subjective matter. – Ezarate11 Apr 03 '19 at 10:11
10

There's an alternative that's quite unreadable in my opinion but I'll share anyway just as a curiosity:

x = (i>100 and 2) or (i<100 and 1) or 0

More info here: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not

Ariel
  • 3,383
  • 4
  • 43
  • 58
8

You can optionally actually use the get method of a dict:

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

You don't need the get method if one of the keys is guaranteed to evaluate to True:

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

At most one of the keys should ideally evaluate to True. If more than one key evaluates to True, the results could seem unpredictable.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Shane
  • 4,875
  • 12
  • 49
  • 87
  • You're right, this would not work if you are trying to evaluate a number being less than multiple other numbers, in order to figure out the position of that number (i.e. is n < 10, else if n < 20, else if n < 50; in this particular case, if the number is 1, all comparisons are True). – OzzyTheGiant Apr 20 '22 at 19:08
8

yes you can by doing this :

i = int(input('type your num here : '))

x = 2 if i > 100 else ( 1 if i < 100 else 0)
print (x)
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
HolakoNoob
  • 81
  • 1
  • 2
7
if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

If you want to use the above-mentioned code in one line, you can use the following:

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

On doing so, x will be assigned 2 if i > 100, 1 if i < 100 and 0 if i = 100

7

The ternary operator is the best way to a concise expression. The syntax is variable = value_1 if condition else value_2. So, for your example, you must apply the ternary operator twice:

i = 23 # set any value for i
x = 2 if i > 100 else 1 if i < 100 else 0
alfredo
  • 524
  • 6
  • 9
4

People have already mentioned ternary expressions. Sometimes with a simple conditional assignment as your example, it is possible to use a mathematical expression to perform the conditional assignment. This may not make your code very readable, but it does get it on one fairly short line. Your example could be written like this:

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

The comparisons would be True or False, and when multiplying with numbers would then be either 1 or 0. One could use a + instead of an | in the middle.

Ant6n
  • 1,887
  • 1
  • 20
  • 26
4

Nested ternary operator is the best solution --

Example case -

4 = 1

3 = 2

2 = 3

1 = 4
a = 4

prio = 4 if a == 1 else (3 if a == 2 else (2 if a == 3 else 1))
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Blue Bird
  • 193
  • 3
  • 8
3

It also depends on the nature of your expressions. The general advice on the other answers of "not doing it" is quite valid for generic statements and generic expressions.

But if all you need is a "dispatch" table, like, calling a different function depending on the value of a given option, you can put the functions to call inside a dictionary.

Something like:

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

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

Instead of an if-else:

if option=="save":
    save()
...
Emma
  • 27,428
  • 11
  • 44
  • 69
jsbueno
  • 99,910
  • 10
  • 151
  • 209
0

You can use nested ternary if statements.

# 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
  • 159
  • 1
  • 4
0
MESSAGELENGHT = 39
"A normal function call using if elif and else."
if MESSAGELENGHT == 16:
    Datapacket = "word"
elif MESSAGELENGHT == 8:
     Datapacket = 'byte'
else:
     Datapacket = 'bit'

#similarly for a oneliner expresion:
    

Datapacket = "word" if MESSAGELENGHT == 16 else 'byte' if MESSAGELENGHT == 8 else 'bit'
print(Datapacket)

Thanks