Python:为什么2D列表理解需要在内循环之前先使用外循环?

时间:2019-03-03 01:05:08

标签: python list-comprehension

table = [[1, 11, 111], [2, 22, 222], [3, 33, 333]]
[cell for cell in row for row in table] # Error
[cell for row in table for cell in row] # [1, 11, 111, 2, 22, 222, 3, 33, 333]

直觉上,第一个列表理解更有意义。它正在从特定性变为不太特定性,即单元格->行->表。 (我发现这对Python列表理解确实很奇怪,它应该是表格->行->单元格,但我离题了。)

单元格->表->行背后的逻辑是什么?解析器如何看待这一点?

4 个答案:

答案 0 :(得分:2)

for循环的含义与您以“常规”方式写出来的循环相同:

for row in table:
    for cell in row:
        print(cell)

因此,当您将其放入列表推导中时,您可以按原样保留循环(除去“:”除外),而只需将最终表达式拉到开头即可。

# you can actually "abuse" list comprehensions to have short
# loops like this, even if you don't care about the list being
# generated. It's generally not a great practice though
[print(cell) for row in table for cell in row]

我承认当您从左到右阅读代码时,这有点令人困惑。您只需要记住要先阅读循环,然后在开头声明开始。我想它可以实现为

[for row in table for cell in row cell]

但我认为这看起来更加令人困惑;很难说出第二个循环在哪里结束以及其中的语句开始于哪里。最后,这是一个设计决定,尽管我确信有些人会发现一种方法或另一种方法更加直观。

答案 1 :(得分:2)

我同意您的第一次尝试总体上更直观,因为它更紧密地模仿了我,也许大多数人是如何考虑从更具体到更不具体的事情进行迭代的。

嵌套的python列表推导是从嵌套的for循环中改编而成的:

for row in table:
    for cell in row:
        cell

连接行:

for row in table: for cell in row: cell

将其包装在列表括号中,删除:,然后将重复的表达式移到最前面:

[cell for row in table for cell in row]

答案 2 :(得分:1)

解析器如何看待这个?

Python中此类表达式的语法规则称为“显示”。您可以找到定义here

comprehension ::=  expression comp_for
comp_for      ::=  ["async"] "for" target_list "in" or_test [comp_iter]
comp_iter     ::=  comp_for | comp_if
comp_if       ::=  "if" expression_nocond [comp_iter]
  

新容器的元素是通过将每个for或if子句考虑为一个块,从左向右嵌套并评估表达式以每次生成一个元素而产生的元素到达最里面的方块。

     

最左中的for子句中的可迭代表达式在封闭范围内直接求值,然后作为参数传递给隐式嵌套范围。后续的for子句和最左边的for子句中的任何过滤条件都无法在封闭范围内进行评估,因为它们可能取决于从最左边的iterable获得的值。

以您的示例为例:

[cell for row in table for cell in row]

解释器将按以下方式将其分解:

expression = "cell"
comp_for1  = "for row in table" + comp_for2
comp_for2  = "for cell in row"

然后,解释器将在希拉基中重建嵌套循环

comp_for1:
    comp_for2:
        expression

答案 3 :(得分:0)

您会认为理解是for循环的由内而外的版本。至少我起初是这样做的。但是,让我理解它的最简单方法是,在第一次尝试时,请注意您会在定义之前先调用变量 row在定义之前被调用。因此,从逻辑上讲,您会得到一个错误。

[cell for cell in row ...]

row未定义

[cell for row in table for cell in row]

这里没有问题