元素顺序
PEP 202 不是很...全面,但您可以在Python Language Reference 中找到一些信息:
理解由一个表达式组成,后跟至少一个 for 子句和零个或多个 for 或 if 子句。在这种情况下,新容器的元素是通过将每个 for 或 if 子句视为一个块,从左到右嵌套,并在每次到达最里面的块时评估表达式以产生一个元素而产生的元素。
[...]
最左边 for 子句中的可迭代表达式直接在封闭范围内求值,然后作为参数传递给隐式嵌套范围。
因此列表理解从左到右进行for 块。
但在你的情况下,你有两个列表推导,每个都有一个块:
- 外部列表理解:为
matrix 中的每个row 做一些事情;
- 内部列表理解(用
row 做某事):为row 中的每个x 做其他事情。
这就是为什么你的列表理解最好从右到左阅读。
使用函数更容易看到:
>>> def square_elements(row): return [x**2 for x in row] # inner
...
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [square_elements(row) for row in matrix] # outer
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]
现在考虑两个块列表理解:
>>> [x**2 for row in matrix for x in row]
[1, 4, 9, 16, 25, 36, 49, 64, 81]
您会看到从左到右的顺序。在第一种情况下,您有:为matrix 中的每个row 做一些事情,而这就是:为row 中的每个x 做一些其他事情。在第二种情况下,它是:为matrix 中的每个row 中的每个x 做一些事情。
执行顺序
这就是你问的问题,即使我不确定这是你想问的问题!操作按什么顺序执行?规范似乎对这个问题没有任何说明,但答案是:没关系,只要您避免列表推导中的副作用。如果您从列表推导式中得到一个列表(不引发异常),则无论它是如何构建的,都可以保证完成此列表。
但如果您不遵循“无副作用”的规则,则执行副作用的顺序可能会改变最终结果。
你可以使用一个技巧来测试它:print 函数返回None,因此if not print(...) 总是True:
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> squared = [[x**2 for x in row if not print("value", x)] for row in matrix if not print("row", row)]
row [1, 2, 3]
value 1
value 2
value 3
row [4, 5, 6]
value 4
value 5
value 6
row [7, 8, 9]
value 7
value 8
value 9
>>> squared
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]
顺序似乎“自然”,但我认为您不应该依赖它(更重要的是:您的列表推导中不应有副作用)。