Inconsistent comprehension syntax?

2019-01-20 07:55发布

I just stumbled over what seems to be a flaw in the python syntax-- or else I'm missing something.

See this:

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

But this is a syntax error:

[x for x in range(30) if x % 2 == 0 else 5]

If you have an else clause, you have to write:

[x if x % 2 == 0 else 5 for x in range (30)]

But this is a syntax error:

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

What am I missing? Why is this so inconsistent?

3条回答
Evening l夕情丶
2楼-- · 2019-01-20 08:37

You are mixing syntax here. There are two different concepts at play here:

  • List comprehension syntax. Here if acts as a filter; include a value in the iteration or not. There is no else, as that is the 'don't include' case already.

  • A conditional expression. This must always return a value, either the outcome of the 'true' or the 'false' expression.

查看更多
不美不萌又怎样
3楼-- · 2019-01-20 08:40

What am I missing?

The following is a ternary operation (aka "conditional expression" in python parlance)

x if some_boolean else y

This evaluates like it reads: if some_boolean is True, give me x, else give me y.

Do not confuse this with comprehension syntax:

(expression) for (iteration variable) in (iterable) [if (filter)]

A conditional expression can go into the (expression) part. It doesn't have anything to do with the optional if (filter) part.

查看更多
The star\"
4楼-- · 2019-01-20 08:55

The difference between the two is that the trailing if in the first one is part of the list comprehension syntax, while the if-else is the conditional operator, not any part of the list comprehension syntax - as it is an expression which is permitted in that part of a list comprehension.

The syntax for the conditional operator is as follows:

x if condition1 else y

This returns the value of the expression that is evaluated, which is why it seems to "work" for your case, though it evaluates all of the time and returns always - which is the key difference between the two.

Meanwhile, for the list comprehension, it tests whether or not the condition applies, and does not add that in the new list created if the condition does not evaluate to true according to the Truth Value Testing procedure, not None nor anything else.

Compare the following (taking an example from PEP202):

a = [i if i % 2 == 0 else None for i in range(20)]
b =  [i for i in range(20) if i % 2 == 0]

a would be

[0, None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None]

while b would be

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

which isn't the same at all, as no matter what the result of it is, it will still add it in if there is no if part of the list comprehension.

查看更多
登录 后发表回答