Python多重if条件列表推导式

67
我们都知道Python的。
[f(x) for x in y if g(x)]

语法。

然而,列表推导的AST表示形式可以容纳多个'if'表达式:

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

有人可以给我一个Python代码的例子,可以生成具有多个'if'表达式的AST吗?

5个回答

106
只需将它们一个接一个地堆叠即可:
[i for i in range(100) if i > 10 if i < 50]

生成11到49之间(包括11和49)的整数。


16
当使用“and”可以达到完全相同的结果时,为什么需要这个? - Will Vousden
23
实际上,你甚至可以写成if 10 < i < 50 - tobias_k
5
@EmilVikström,我刚碰到这个问题并看到了你的评论。有时候你确实想要一个嵌套的if语句(而不是逻辑上的“与and”)。例如,如果你想引用一个包含某个键的字典但首先必须确保该键存在。使用嵌套的if语句,你可以先检查有效性然后避免出现错误。 - Adi Sarid
13
@AdiSarid,但Python在and运算符附近具有惰性求值的特性,因此您可以在and左侧进行健全性检查,以防止对右侧的求值。 - Emil Vikström
9
@horcle_buzz,请阅读我在上面回复Adi Sarid的评论。 - Emil Vikström
显示剩余3条评论

79

语法允许多个if语句,因为你可以将它们与for循环混合使用:

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

理解组件应被视为嵌套语句,上述内容可翻译为:

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

这也意味着您可以在没有for循环的情况下使用多个if语句:

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

虽然毫无意义(只是使用and或链式运算符将它们组合起来),但它仍然可以翻译成一个合法的嵌套语句:

尽管没有意义(只是通过使用 and 运算符或链接运算符把它们组合在一起),但仍然可以转化为合法的嵌套语句:
lst = []
for i in range(100):
    if i > 10:
        if i < 20:
            lst.append(i)

语法和解析器并没有特别禁止这种用法,就像Python不会禁止你嵌套if语句一样。

注意PEP 202 - 列表推导式(最初将该功能添加到语言中的提案文档)实际上在示例部分包括了一个双重if推导式:

>>> 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')]

4
实际上,AST语法中引用的部分并不是处理你回答的第一部分所必需的。那个例子将创建两个带有单个if语句的推导生成器(comprehension generator) - poke

23

使用内置的all()函数可以让你把多个布尔表达式或函数放在可迭代对象中,并嵌入到推导式中。我认为这是一个相当未被充分利用的内置函数,它可以保持代码的可读性。

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

或者

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

如果只需要满足一个条件,any() 内置函数也可以很好地工作:


>>> [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]

3
请注意,使用all()时条件将始终被评估(没有短路优化),而且需要为循环的每个元素创建一个列表。 - Elias Dorneles
5
allany都会进行短路求值,但要充分利用这一点,你需要向它们传递一个生成器表达式而不是列表推导式。 - PM 2Ring

8

语言参考资料更好地解释了这个概念:

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]

正如您所看到的,列表推导式是以可选的list_iter结尾定义的——一个单独的list_iter。现在,这个list_iter可以是列表推导式的另一个for部分,也可以是if条件。if条件本身再次以另一个可选的list_iter结束。这是必要的,以便在同一列表推导式中链接多个具有可选if条件的for部分。您也可以构造一个.. if X if Y if Z部分用于list_iter,这只是一个副作用。

因此,虽然仅链式多个if条件的可能性并不需要,但它允许整个语法以这种方式定义。


0

这是一个使用多个'if'的列表推导式示例

代码语法

 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)

欢迎!问题是要求在列表推导式中使用多个if语句的示例,而不是一般情况下使用if语句的列表推导式的示例。你能编辑你的回答来解决多个if语句的问题吗? - Kyle Alm
欢迎!问题要求提供在列表推导式中使用多个if语句的示例,而不是一般带有if语句的列表推导式的示例。您能否编辑您的答案以解决多个if语句的问题? - Kyle Alm
1
@KyleAlm 谢谢。在回复其他答案时,我把它放错了地方,我很抱歉。 - Jeewan Ghimire
@JeewanGhimire 你的回答与10年前已经被接受的答案有何不同之处? - NotTheDr01ds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接