Why is this list comprehension giving me a syntax

2019-06-04 00:38发布

问题:

This question already has an answer here:

  • if else in a list comprehension [duplicate] 8 answers

I have the following list comprehension.

return [tower for tower in state if tower != space else []]

But when I run it, python spits back this error:

return [tower for tower in state if tower != space else []]  
                                                      ^
    SyntaxError: invalid syntax

If I remove the else statement, it runs fine. Am I writing the else statement wrong somehow?

回答1:

List comprehensions support if but not else because the if section filters elements, you either include an element or you don't include it, a boolean choice.

If you wanted to use a conditional expression to build the iterable part of the for loop, use parentheses:

return [tower for tower in (state if tower != space else [])]  

but I suspect that you wanted to alter the value of the expression in the element expression instead; that's not filtering, you are simply producing a different value for certain items. Use a conditional expression to produce your values:

return [tower if tower != space else [] for tower in state]  

or if you really wanted to filter, simply omit the else:

return [tower for tower in state if tower != space]  

When constructing a list comprehension, remember that you need to read the expression as nested from left to right, with the final expression producing the result out on the left:

[element_producing_expression for name in iterable if filter_expression]

is the moral equivalent of:

for name in iterable:
    if filter_expression:
        element_producing_expression

where you can use as many nested loops and if filters as your use case requires.

The three options I described above are then the same as:

# conditional expression producing the iterable
for tower in (state if tower != space else []):
    tower 

# conditional expression in the element expression
for tower in state:
    tower if tower != space else [] 

# filtering expression with no else
for tower in state:
    if tower != space:
        tower


回答2:

You are putting the else in the for clause of the comprehension, but you need to put the entire if/else expression in the target expression:

[tower if tower != space else [] for tower in state]

When you use for tower in state if <condition> you are saying you want to not even make use of items in state if they don't satisfy the condition. In this case, you can't use an else, because all you can do is either process each item (including something in the list comprehension result), or not.

The X if Y else Z, on the other hand, is a normal expression that can be used as the target expression of the list comprehension. This means that every element in the source iterable will generate an element in the result, but the if/else determines what that result item will be.



回答3:

How about this:

[tower if tower != space else [] for tower in state]


回答4:

That's because python doesn't support if-else in list comprehension filters, only if clauses.

You can however achieve the result you want by using a conditional expression

 [tower if tower != space else [] for tower in state]