【问题标题】:python list comprehension with multiple 'if's具有多个'if's的python列表理解
【发布时间】:2013-02-21 07:09:55
【问题描述】:

我们都知道python的

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

语法。

然而 AST 列表理解的表示有多个“if”表达式的空间:

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

谁能给我一个 Python 代码示例,它会生成一个带有多个“if”表达式的 AST?

【问题讨论】:

    标签: python if-statement list-comprehension


    【解决方案1】:

    把它们一个接一个地叠起来:

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

    产生介于 11 和 49 之间的整数。

    【讨论】:

    • and 达到完全相同的结果时,为什么需要这样做?
    • 其实你甚至可以写if 10 &lt; i &lt; 50
    • @EmilVikström 刚刚遇到了这个问题和您的评论。有时您确实需要嵌套的 if(而不是逻辑“and”)。例如,如果您想使用某个键引用字典,但首先您必须确保该键存在。使用嵌套的 if 可以先检查有效性,然后避免错误。
    • @AdiSarid 但 Python 对 and 周围的操作数有惰性求值,因此您可以在 and 的左侧进行完整性检查,并防止右侧被求值。
    • @horcle_buzz 阅读上面我对 Adi Sarid 的评论。
    【解决方案2】:

    语法允许多个 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)
    

    这也意味着您可以使用多个 if 语句,而两者之间没有 for 循环:

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

    虽然没有意义(只需将使用 and 或链式运算符的那些组合起来),它仍然可以转换为合法的嵌套语句集:

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

    语法和解析器并没有明确禁止这种用法,就像 Python 不允许您嵌套 if 语句一样。

    请注意,PEP 202 – List Comprehensions(将这个特性添加到语言中的原始提案文档)实际上在示例部分包含了双如果理解:

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

    【讨论】:

    • 实际上,AST 语法的引用部分不是处理您答案的第一部分所必需的。该示例将创建两个 comprehension generator,每个都有一个 if 语句。
    【解决方案3】:

    使用内置的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]
    

    【讨论】:

    • 请注意,使用 all() 将始终评估条件(无短路优化),另外它需要为循环的每个元素创建一个列表。
    • @elias all & any 短路。但要充分利用这一点,您必须向它们传递一个生成器表达式,而不是列表推导式。
    【解决方案4】:

    language reference 对此提供了更好的想法:

    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-part 或if 条件。 if 条件本身再次以另一个可选的list_iter 结束。这对于在同一个列表理解中使用可选的 if 条件链接多个 for-parts 是必不可少的。您还可以为list_iter 构造一个.. if X if Y if Z 部件这一事实只是一个副作用。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-29
      • 2021-12-08
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多