vec = [[1,2,3], [4,5,6], [7,8,9]]
print [num for elem in vec for num in elem] <----- this
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
这让我感到困惑。
我理解for elem in vic
中的elem
是列表中的列表。
但我不太明白一开始和结尾处的num
和for num in elem
的用法。
Python如何解释这个代码?
它的执行顺序是怎样的?
vec = [[1,2,3], [4,5,6], [7,8,9]]
print [num for elem in vec for num in elem] <----- this
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
这让我感到困惑。
我理解for elem in vic
中的elem
是列表中的列表。
但我不太明白一开始和结尾处的num
和for num in elem
的用法。
Python如何解释这个代码?
它的执行顺序是怎样的?
让我们来分解一下。
一个简单的列表推导式:
[x for x in collection]
如果我们将其分解成几个部分,就容易理解了:[A for B in C]
A
是结果列表中的项B
是集合C
中的每一项C
是集合本身。通过这种方式,可以编写如下代码:
[x.lower() for x in words]
为了将列表中的所有单词转换为小写。
[x for y in collection for x in y] # [A for B in C for D in E]
在这里,有些特别的事情发生了。我们希望最终列表包括A
项,而A
项在B
项中找到,因此我们需要告诉列表推导式。
A
是将出现在结果列表中的项B
是集合C
中的每个项C
是集合本身D
是集合E
中的每个项(在这种情况下也是A
)E
是另一个集合(在这种情况下为B
)这个逻辑类似于常规的for循环:
for y in collection: # for B in C:
for x in y: # for D in E: (in this case: for A in B)
# receive x # # receive A
为了更好地解释并给出一个很好的例子+解释,想象一下有一辆火车。
火车头(前面)永远会存在(列表推导式的结果)
然后,有任意数量的火车车厢,每个火车车厢都采用以下形式:for x in y
列表推导式可能是这样的:
[z for b in a for c in b for d in c ... for z in y]
这就像是有一个常规的 for 循环:
for b in a:
for c in b:
for d in c:
...
for z in y:
# have z
换句话说,在列表推导式中,不需要换行和缩进,只需将下一个循环添加到末尾。
回到列车类比:
Engine
- Car
- Car
- Car
... Tail
什么是“Tail”?在列表推导式中,“Tail”是一种特殊的东西。你不需要一个,“Tail”是一个条件。看这个例子:
[line for line in file if not line.startswith('#')]
只要一行不以井号(#
)开头,这将会返回文件中的每一行,其他的行则被跳过。
使用“尾部”的技巧是,在所有循环结束后,同时检查其为True/False,并获得最终的“引擎”或“结果”。在常规for循环中,上述示例如下:
for line in file:
if not line.startswith('#'):
# have line
请注意:虽然我的火车类比中只有在火车尾部存在一个“尾巴”,但这个条件或“尾巴”可以出现在每节“车厢”或循环之后...
例如:
>>> z = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> [x for y in z if sum(y)>10 for x in y if x < 10]
[5, 6, 7, 8, 9]
在常规的for循环中:>>> for y in z:
if sum(y)>10:
for x in y:
if x < 10:
print x
5
6
7
8
9
if
语句。这是不正确的。你可以在列表推导式的任何级别上使用 if 语句,甚至可以将多个 if 语句放在一起(尽管在你意识到它们是嵌套的之前,这看起来有点荒谬)。你只是不能将 if
用作第一个项目,必须是一个 for
循环。 - Martijn PietersA for B in C for D in E
扩展成一个嵌套循环,包括 for B in C:
和 for A in B
,丢弃 for D in E
部分时。 - Martijn Pieters从列表推导式文档中可知:
当提供列表推导式时,它由单个表达式组成,后跟至少一个
for
子句和零个或多个if
子句。在这种情况下,新列表的元素是通过将每个for
或if
子句视为块,从左到右嵌套,并评估表达式以在达到最内层块时生成列表元素来产生的。
换句话说,假设 for
循环是嵌套的。从左到右读取您的列表推导式可以被嵌套为:
for elem in vec:
for num in elem:
num # the *single expression* from the spec
列表推导式将使用最后一个、最内层的块作为生成结果列表的值。
你可以将列表推导式看作是连续语句。这适用于任何级别的 for
和 if
语句。
例如,考虑带有各自 if
的双重 for
循环:
vec = [[1,2,3], [4,5,6], [7,8,9]]
result = [i for e in vec if len(e)==3 for i in e if i%2==0]
这里的列表推导式与以下代码是相同的:
result = []
for e in vec:
if len(e)==3:
for i in e:
if i%2==0:
result.append(i)
for
和if
而已,不需要缩进但顺序要相同。您的代码相当于:
temp = []
for elem in vec:
for num in elem:
temp.append(num)
for
语句的书写顺序与您只编写常规for
循环时所编写的顺序相同。 - kindall