目录
语法
分类
列表推导式
集合推导式
字典推导式
推导式(comprehensions),又称解析式,是 Python 中常见的语法糖。推导式可以从一个数据序列构建另一个新的数据序列,常用于数据处理场景。
表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]
其中 if
条件判断根据需要,可有可无。
推导式的核心为 for 循环。根据返回对象的不同,推导式可区分为列表推导式,字典推导式,结合推导式等。不同推导式在语法上基本一致。
列表推导式(list comprehension)是一种简化的 for 循环创建列表,为最常见的推导式。
例 1
>>> l = []
>>> for i in range(5):
l.append(i)
>>> l
[0, 1, 2, 3, 4]
上述 for 循环转换为列表推导式则为:
>>> l = [l for l in range(5)]
>>> l
[0, 1, 2, 3, 4]
可见,与单纯 for 循环相比,作为语法糖,列表推导式简化了代码,返回新的列表。
列表推导式也可以应用于相对复杂的场景:
例 2
>>> evens = [i for i in range(10) if i % 2 == 0]
>>> evens
[0, 2, 4, 6, 8]
例 3
>>> l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> l = [l[i][i] for i in range(len(l))]
>>> l
[1, 5, 9]
例 4
>>> l = [lambda x: x* i for i in range(3)]
>>> type(l[0]), "---", l[0])
--- . at 0x7f9e19ab00>
>>> l[1](2)
4
更可以实现复杂的嵌套循环:
例 5
>>> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
>>> l = [i for row in matrix for i in row]
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
若以 for 循环来表示,则为:
>>> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
>>> l = []
>>> for row in matrix:
for i in row:
l.append(i)
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
例 6
>>> l = [x**y+z for x in range(2) for y in range(3) for z in range(4)]
>>> l
[1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
例 7
>>> names = [['Billy', 'Jefferson', 'Andrew', 'Wesley', 'Joe'],
['Steven', 'Alice', 'Jennifer', 'Eva', 'Sherry']]
>>> print([name for i in names for name in i if name.count('e') >= 2])
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
例 8
>>> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
>>> print([[row[i] for row in matrix] for i in range(3)])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
该例嵌套了内外循环,等价于
>>> l = []
>>> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
>>> for i in range(3):
temp = []
for row in matrix:
temp.append(row[i])
l.append(temp)
>>> print(l)
通过上述示例,可见:
毋庸置疑,列表推导式以一行代码之简,挽多行代码之繁。但正如一个硬币有其两面, 多个表达式和可迭代对象融入一行代码,不可避免带来可读性降低的问题,有时甚至晦涩难懂,且出错后难以排查。且随着一行代码的延长,甚至超过代码规范的长度(一般为80个字符),更使得代码的理解变得困难。因此,适可而止是为上策。
有时,面对长长的推导式,可采用断行的方式予以处理,以便理解。
例 2
evens = [
i
for i in range(10)
if i % 2 == 0
]
例 7
[
name
for i in names
for name in i
if name.count('e') >= 2
]
如果把列表推导式的 [] 替换为 (),则变为生成器(generator )表达式。
例 8
>>> g = ( i for i in range(6)) >>> g
at 0x7f7f201e00> >>> list(g) [0, 1, 2, 3, 4, 5] >>> list(g) [] 生成器推导式与列表推导式的区别在于:
- 生成器表达式一次遍历,随后清空生成器对象,因此比列表推导式速度更快,占用的内存也更少。
- 返回值不同。列表推导式返回新列表。生成器表达式返回生成器对象。
生成器表达式的返回结果可以根据需要转化为列表或元组,也可以 for 或 __next__() 方法或内置函数 next() 遍历:
例 9
>>> g = (i for i in '上帝与你同在') >>> for i in g: print(i) 上 帝 与 你 同 在 >>> g = (i for i in '上帝与你同在') >>> next(g) '上' >>> next(g) '帝' >>> g.__next__() '与' >>> g.__next__() '你'
集合推导式跟列表推导式非常相似,唯一区别在于用 {} 代替 []。
例 10
>>> S = {x for x in range(10) if x % 2 == 0}
>>> S
{0, 2, 4, 6, 8}
例 11
>>> names = ['Billy', 'Jefferson', 'Andrew', 'Wesley', 'Joe']
>>> S = {name[0] for name in names}
>>> S
{'A', 'W', 'B', 'J'}
字典推导式为列表推导式思想的延续,语法差不多,只不过返回的是字典而已。
例 12
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> print({d[k]: k for k in d})
{1: 'a', 2: 'b', 3: 'c'}
例 13
>>> d = {'a': 4, 'B': 3, 'c': 2, 'D':1}
>>> print({i.lower(): d.get(i.lower(), 0) + d.get(i.upper(), 0) for i in d.keys()})
{'a': 4, 'b': 3, 'c': 2, 'd': 1}
注:
1、关于语法糖,请参见:Python 之语法糖手到擒来的快感https://blog.csdn.net/iprobobo/article/details/1235688392、关于列表,请参见:Python 序列之三言两语序列是具有先后关系的一组元素...https://blog.csdn.net/iprobobo/article/details/122542937
3、关于集合,请参见:Python 集合之 abc集合之合集https://blog.csdn.net/iprobobo/article/details/122511498
4、关于字典,请参见:Python 字典之演义映射无处不在,键值对无处不在。https://blog.csdn.net/iprobobo/article/details/122668767