具有多个'if'的python列表理解

Ste*_*fan 37 python if-statement list-comprehension

我们都知道python的

[f(x) for x in y if g(x)]
Run Code Online (Sandbox Code Playgroud)

句法.

但是 ,列表推导的AST表示有多个'if'表达式的空间:

comprehension = (expr target, expr iter, expr* ifs)
Run Code Online (Sandbox Code Playgroud)

有人能给我一个python代码的例子,它会产生一个带有多个'if'表达式的AST吗?

Mar*_*ers 51

语法允许多个if语句,因为您可以在for循环之间混合它们:

[j for i in range(100) if i > 10 for j in range(i) if j < 20]
Run Code Online (Sandbox Code Playgroud)

理解组件应该被视为嵌套语句,上面翻译为:

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

这也意味着您可以使用多个if语句而不需要for循环:

[i for i in range(100) if i > 10 if i < 20]
Run Code Online (Sandbox Code Playgroud)

虽然非敏感(只是将那些使用and或与链式运算符组合在一起),但它确实转换为合法的嵌套语句集:

lst = []
for i in range(100):
    if i > 10:
        if i < 20:
            lst.append(i)
Run Code Online (Sandbox Code Playgroud)

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

请注意,PEP 202 - 列表理解(将此功能添加到语言中的原始提案文档)实际上包含示例部分中的双重理解:

>>> 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')]
Run Code Online (Sandbox Code Playgroud)

  • 实际上,AST语法的引用部分不是处理答案第一部分所必需的.该示例将创建两个*理解生成器*,每个*都包含一个if语句. (3认同)

Emi*_*röm 50

只需将它们堆叠在一起:

[i for i in range(100) if i > 10 if i < 50]
Run Code Online (Sandbox Code Playgroud)

产生11到49之间的整数.

  • 事实上,你甚至可以写"如果10 <i <50". (14认同)
  • 当`和`达到完全相同的结果时,为什么需要这个? (8认同)
  • @AdiSarid但Python对`和`周围的操作数进行了懒惰的评估,因此你可以在`和`的左侧进行完整性检查,并防止被评估的右侧. (7认同)
  • @horcle_buzz阅读上面对Adi Sarid的评论. (6认同)
  • @EmilVikström刚刚遇到了这个问题和你的评论.有时您确实需要嵌套if(而不是逻辑"和").例如,如果要引用具有某个键的字典,但首先必须确保该键存在.如果您可以先检查有效性,然后避免错误. (4认同)
  • 那么这是一个合乎逻辑的AND? (3认同)

kyl*_*e.a 13

使用内置all()函数允许您在迭代中放置多个布尔表达式或函数,并坚持您的理解.我认为这是一个非常使用的内置并且它保持高可读性.

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

要么

>>> [x for x in range(20) if all([foo(x), bar(x)])]
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

  • @elias`all`&`any`*do*short-circuit.但要充分利用它,你必须传递一个生成器表达式,而不是列表理解. (3认同)
  • 请注意,使用all()将始终评估条件(无短路优化),此外还需要为循环的每个元素创建一个列表. (2认同)

pok*_*oke 5

语言参考提供了有关这个更好的主意:

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]
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,列表理解是list_iter在末尾用可选项定义的list_iter.现在,这list_iter可以是列表理解的另一部分或if条件.if条件本身再次以另一个可选项结束list_iter.这对于在同一列表理解中使用可选的if条件链接多个for-parts是必要的.你也可以为它构建一个.. if X if Y if Z部分的事实list_iter只是一个副作用.

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