前面我们详细介绍了 for 循环的操作细节。其实,还有一个“精简”版的 for 循环,称为推导式(comprehensions,又称解析式),它是 Python 中的一种独有特性。它能够非常简洁地按照某种规则,以一个数据序列(如列表、字典和集合等)为基础,推导出另一个新的数据序列。
推导式共有三种类型,分别是列表推导式、字典推导式和集合推导式。本节教程我们先来介绍列表推导式。
Python列表推导式概念
列表推导式的语法形式非常简单,如下所示:
[生成表达式 for 变量 in 序列或迭代对象]
最外层的方括号是列表的标志性身份,它表明这个表达式的结果是生成一个列表,故称列表推导式(list comprehensions)。在功能上,方括号内描述的列表推导式相当于一个循环,只不过形式更加简洁罢了。
图 1 给出了代码说明。
图 1:基于 for 循环的列表推导式
Python列表推导式功能
1.过滤原始序列中不符合条件的元素
在列表推导式中,我们可以通过 if 语句的逻辑判断,筛选符合条件的元素。例如,如果我们想把一个列表中的整数提取出来,并做平方处理,可以通过如图 2 所示的方法来实现。
图 2:通过列表推导式筛选元素
2.使用列表推导式实现嵌套列表的平铺
在前面的列表推导式例子里,我们仅使用一层 for 循环来产生新的列表。事实上,我们也可以使用两层 for 循环。
下面的代码就是利用两层 for 循环将嵌套列表平铺成一个列表的示例:
In [9]: vec = [[1,2,3],[4,5,6], [7,8,9]]
In [10]: flat_vec = [num for elem in vec for num in elem]
In [11]: print(flat_vec)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
这个列表推导式中包括两个 for 循环,其中,第一个 for 循环可视为外循环,第二个循环可视为内循环。外循环每读取一个元素(某个内部列表元素,如 [1,2,3]),内循环要遍历列表元素中的三个子元素(如 1、2、3)。很显然,外循环跑得慢,而内循环跑得快。方括号最前方的那个 num,就是所谓的输出表达式,虽然它看起来就是一个变量模样。
3.多条件组合构造特定列表
如前所述,列表推导式包含一对括号,在括号中有一个输出表达式,表达式后面紧跟一条 for 语句,然后是 0 条或多条 for 语句、if 语句,通过各种组合,能够构造出各类高阶列表。
例如,下面的列表推导式将两个不同列表中的元素整合到了一起。
In [12]: new_list = [(x,y) for x in [1,2,3] for y in [3,1,4] if x!=y]
In [13]: print(new_list)
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
需要注意的是,如果表达式是一个元组,如 In [12] 处的 (x,y),那么必须得给它加上括号。
通过前面的讲解,我们知道,在 In [12] 处的一条语句,相当于两个嵌套的 for 循环,内循环中添加了一个 if 语句,与其等价的常规 for 循环代码如下所示。
In [14]: new_list = []
In [15]: for x in [1, 2, 3]:
...: for y in [3, 1, 4]:
...: if x != y :
...: new_list.append((x, y))
...:
In [16]: print(new_list)
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
对比上述两段功能相同的程序,我们要注意两点:
第一,在列表推导式所表征的代码中,for 和 if 等逻辑控制关键词出现的顺序,与常规代码中 for 和 if 等关键词出现的顺序是相同的;
第二,列表推导式的代码是简单的,但等价的常规代码可读性更强,具体哪种更好,仁者见仁,智者见智。