2

I have two list comprehensions where conditions are defined in different places.

>>> [ x**2 if x%2==0 else x**3 if x%3==0 else 0 for x in range(10)]
[0, 0, 4, 27, 16, 0, 36, 0, 64, 729]

>>> [ x**2 if x%2==0 for x in range(10) ]
  File "<stdin>", line 1
    [ x**2 if x%2==0 for x in range(10) ]
                       ^
SyntaxError: invalid syntax

However if i do this:

>>> [ x**2 for x in range(10) if x%2==0 ]
[0, 4, 16, 36, 64]
>>> 

it works.

Now the confusing part is how the order is evaluated. What is the difference?

bluefoggy
  • 761
  • 1
  • 7
  • 20

4 Answers4

5

You have two different concepts confused here.

An expression like x**2 if x%2==0 else x**3 is a conditional expression. They can be chained, but the else is not optional - because this is a self-contained expression that evaluates to a single, specific value. The else x**3 is required because Python has to know what the expression evaluates to whenever it is not the case that x % 2 == 0.

In a list comprehension, when you write things like [x**2 for x in range(10) if x%2==0], the if clause is used to filter the x values found in range(10), for which elements of the resulting list are computed. There is no else permitted here because the purpose is entirely different.

You can mix and match: [x**2 if x%2 == 0 else x**3 for x in range(10) if x%3 == 0]. Now if x % 3 == 0 is being used to decide which x values to compute a result for, and if x%2 == 0 is being used to decide whether to use x**2 or x**3 as the computed result for those xs.

Karl Knechtel
  • 51,161
  • 7
  • 77
  • 117
1

You are confusing two completely different constructs.

Conditions for list comprehensions can be defined only at one plance, at the end, and they act like filters:

[ ... for ... if .... ]

The other construct you see is python's version of the ternary operator. It's not a filter, it just selects one of the expressions based on the logical value of a third expression:

... if ... else ...
Community
  • 1
  • 1
Karoly Horvath
  • 88,860
  • 11
  • 107
  • 169
  • 1
    `if` in the list comprehension can be placed anywhere except before the first `for`: `[x for x in [1,2,3] if x < 2 if x < 4 for j in [x]]` – falsetru Sep 14 '14 at 08:43
  • It's not a [nested comprehension](https://docs.python.org/3/tutorial/datastructures.html#nested-list-comprehensions). – falsetru Sep 14 '14 at 08:49
0

from the docs:

A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it.

so, by definition the if comes after the for.

WeaselFox
  • 6,770
  • 6
  • 39
  • 72
0

For example, this:

[ x**2 if x%2==0 else x**3 if x%3==0 else 0 for x in range(10)]

Is the equivalent of this:

>>> l = []
>>> for x in range(10):
...     l.append(x**2 if x%2==0 else x**3 if x%3==0 else 0)
... 
>>> l
[0, 0, 4, 27, 16, 0, 36, 0, 64, 729]

I.e. there is no if statement, but rather an if expression. So there's always something appended to the list on every step of the for.

However when you do this:

[ x**2 for x in range(10) if x%2==0 ]

And if statement will be used. And not all steps will append to the list. Translated into:

>>> l = []
>>> for x in range(10):
...     if x%2==0:
...             l.append(x**2)
... 
>>> l
[0, 4, 16, 36, 64]
Alexandru Chirila
  • 1,984
  • 4
  • 25
  • 39