74

We all know python's

[f(x) for x in y if g(x)]

syntax.

However the AST representation of list comprehension has room for more than one 'if' expression:

comprehension = (expr target, expr iter, expr* ifs)

Can somebody give me an example of python code that would produce an AST with more than one 'if' expression?

0

5 Answers 5

113

Just stack them after one another:

[i for i in range(100) if i > 10 if i < 50]

Produces the integers between 11 and 49, inclusive.

Sign up to request clarification or add additional context in comments.

8 Comments

Why is this needed when and would achieve exactly the same result?
In fact, you could even write if 10 < i < 50.
@EmilVikström Just ran into this question and your comment. Sometimes you do want a nested if (and not a logical "and"). For example if you want to reference a dictionary with a certain key but first you have to make sure the key exists. With a nested if you can first check validity and then avoid an error.
@AdiSarid but Python have lazy evaluation of the operands around and, so you can make your sanity checks on the left hand side of and and prevent the right hand side of being evaluated.
@horcle_buzz Read my comment to Adi Sarid above.
|
83

The grammar allows for multiple if statements because you can mix them between the for loops:

[j for i in range(100) if i > 10 for j in range(i) if j < 20]

The comprehension components should be viewed as nested statements, the above translates to:

lst = []
for i in range(100):
    if i > 10:
        for j in range(i):
            if j < 20:
                lst.append(j)

This also means that you can use multiple if statements without for loops in between:

[i for i in range(100) if i > 10 if i < 20]

Although non-sensical (just combine those using and or with chained operators), it does translate to a legal nested set of statements still:

lst = []
for i in range(100):
    if i > 10:
        if i < 20:
            lst.append(i)

The grammar and parser do not specifically disallow such usage, in the same way that Python doesn't disallow you to nest if statements.

Note that PEP 202 – List Comprehensions (the original proposal document that added this feature to the language) actually includes a double-if comprehension in the examples section:

>>> print [(i, f) for i in nums for f in fruit if f[0] == "P" if i%2 == 1]
[(1, 'Peaches'), (1, 'Pears'), (3, 'Peaches'), (3, 'Pears')]

1 Comment

Actually, the quoted part of the AST grammar is not neccessary to handle the first part of your answer. That example will create two comprehension generators with a single if-statement each.
24

Using the built in all() allows you to place multiple Boolean expressions or functions in an iterable and stick in your comprehension. I think it's a pretty under used built in and it keeps readability high.

>>> [x for x in range(20) if all([1 < x < 10, not x & 1])]
[2, 4, 6, 8]

Or

>>> [x for x in range(20) if all([foo(x), bar(x)])]

the any() built in also would work well here if only one condition needed to be satisfied:

>>> [x for x in range(20) if any([1 < x < 10, not x & 1])]
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18]

2 Comments

Note that using all() the conditions will be always evaluated (no short-circuit optimization), plus it needs creating a list for every element of the loop.
@elias all & any do short-circuit. But to get full advantage of that you must pass them a generator expression, not a list comprehension.
8

The language reference gives a better idea about this:

list_comprehension  ::=  expression list_for
list_for            ::=  "for" target_list "in" old_expression_list [list_iter]
list_iter           ::=  list_for | list_if
list_if             ::=  "if" old_expression [list_iter]

As you can see the list comprehension is defined with an optional list_iter at the end—a single list_iter. Now this list_iter can either be another for-part of the list comprehension or an if-condition. The if-condition itself again ends with another optional list_iter. This is essential to make it possible to chain multiple for-parts with optional if-conditions in the same list comprehension. The fact that you could also construct an .. if X if Y if Z part for the list_iter is just a side effect.

So, while the possibility to chain multiple if-conditions alone is not needed, it allows the whole grammar to be defined that way.

Comments

0

Here is an example of using list comprehension with multiple 'if's

code Syntax

 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# List comprehension with multiple 'if' conditions
result = [num for num in numbers if num % 2 == 0 if num > 4]

print(result)

3 Comments

Welcome! The question is asking for examples of using multiple if statements in a list comprehension, not for examples of list comprehensions with if statements in general. Can you edit your answer to address multiple if statements?
@KyleAlm Thanks. It was misplaced while replying to other answer i apologize.
@JeewanGhimire How is your answer any different from the already accepted answer from 10 years ago?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.