One liner with nested if/else conditions

Viewed 113

Real python noob here, and I'm a bit puzzled by looking at the result of this nested if/else one-liner:

>>> num_arr = [5, 10, 15]
>>> [i**2 if i == 10 else i-5 if i < 7 else i+5 for i in num_arr]
[0, 100, 20]

Shouldn't the result be [0, 15, 20] since 10 is greater than 7?

3 Answers

As I mentioned in the comments, the "correct" version (note the parentheses) is:

[(i**2 if i == 10 else i-5) if i < 7 else i+5 for i in num_arr]

Your "problem" stems from the chaining of your if statements, which execute in the English reading order (left to right). So it reads like this:

[i**2 if i == 10 else (i-5 if i < 7 else i+5) for i in num_arr]
  • where i=5, i != 10 in the "first expression", so you move to else; where i < 7 so you get i-5, or 0
  • where i=10, i == 10 so you get i**2, or 100
  • where i=15, i != 10 so you move to else, where i is not less than 7, so you get i+5, or 20

From the documentation:

To make the semantics very clear, a list comprehension is equivalent to the following Python code:

for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # Append the value of
                  # the expression to the
                  # resulting list.

That means yours looks like:

[[expr1] if [condition] else [[expr2] if [condition] else [expr3]] for ...]

Here's the expanded version of the one liner:

for i in num_arr:
    if i == 10:
        i ** 2
    else:
        if i < 7:
            i - 5
        else:
            i + 5

The one-liner if statement is basically: [action] if [condition] else [action]. In other words, do this if said condition is met. Otherwise, do this action.

It's a reason I don't like one-liners is because they become less Pythonic. The code above is more verbose but it's easier to understand.

The value if the condition is True is stated before the if and the value if False is after the else (see https://docs.python.org/2.5/whatsnew/pep-308.html).

Result is i-5 for 5 because i is not 10 but it is < 7

Result is i ** 2 for 10 because i == 10

Result is i + 5 for 15 because i is not 10 and it is not < 7

Hence [0, 100, 20]

Related