55

我们都知道python的

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

句法。

然而,列表推导的 AST表示有多个“if”表达式的空间:

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

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

4

4 回答 4

90

将它们一个接一个地堆叠起来:

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

产生 11 到 49 之间的整数,包括 11 和 49。

于 2013-03-06T13:13:35.473 回答
66

该语法允许多个 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')]
于 2013-03-06T13:16:37.057 回答
17

使用内置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]
于 2015-05-27T14:20:30.397 回答
7

语言参考对此提供了更好的想法:

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

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

于 2013-03-06T13:22:43.300 回答