在编程中,推导式(Comprehension)是一种高效创建数据结构的方式。
在 Python 中,主要有以下几种推导式:
- 列表推导式
- 集合推导式
- 字典推导式
- 生成器推导式
上面几种推导式还可以嵌套调用,用于产生更复杂的数据结构。
列表推导式
列表推导式用于生成一个列表,一般语法形式为:
[expression for item in iterable if condition]
示例如下:
# 生成包含偶数的列表
evens = [i for i in range(10) if i % 2 == 0]
print(evens) # 输出: [0, 2, 4, 6, 8]
# 生成包含奇数的列表
odds = [i for i in range(10) if i % 2 == 1]
print(odds) # 输出: [1, 3, 5, 7, 9]
集合推导式
集合推导式用于生成一个集合,一般语法形式为:
{expression for item in iterable if condition}
示例如下:
# 生成包含偶数的集合
evens = {i for i in range(10) if i % 2 == 0}
print(evens) # 输出: {0, 2, 4, 6, 8}
# 生成包含奇数的集合
odds = {i for i in range(10) if i % 2 == 1}
print(odds) # 输出: {1, 3, 5, 7, 9}
字典推导式
字典推导式用于生成一个字典,一般语法形式为:
{key_expression: value_expression for item in iterable if condition}
示例如下:
# 生成一个字典,值(value)为键(key)的平方
my_dict = {i: i**2 for i in range(3)}
print(my_dict) # 输出: {0: 0, 1: 1, 2: 4}
生成器推导式
生成器推导式用于生成一个生成器对象,一般语法形式为:
(expression for item in iterable if condition)
生成器推导式的语法跟列表推导式类似,只不过把方括号换成圆括号而已。
示例如下:
# 生成一个包含偶数的生成器
evens = (i for i in range(10) if i % 2 == 0)
print(type(evens)) # 输出:
print(next(evens)) # 输出: 0
print(next(evens)) # 输出: 2
嵌套推导式
推导式可以嵌套使用,用于生成更复杂的数据结构。
示例如下:
# 生成一个二维列表
matrix = [[i + j for j in range(3)] for i in range(2)]
print(matrix) # 输出: [[0, 1, 2], [1, 2, 3]]
编码建议
建议一:推导式最好不要超过两个子表达式(两个if条件、两个for循环,一个if条件和一个for循环),子表达式过多会导致可读性变差,如果阅读他人的代码遇到复杂的推导式,可以考虑拆分一下来理解。
上述建议是一个推荐原则,具体实践应该由开发者自己把控。
示例如下:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 直接阅读可能不好理解
filtered_matrix = [[elem for elem in row if elem % 3 == 0] for row in matrix if sum(row) > 10]
print(filtered_matrix) # 输出: [[6], [9]]
# 进行适当的拆分
filtered_matrix = []
for row in matrix:
# 选择总和大于10的行
if sum(row) > 10:
# 保留行中能被3整除的元素
filtered_matrix.append([elem for elem in row if elem % 3 == 0])
print(filtered_matrix) # 输出: [[6], [9]]
建议二:如果推导式中有重复计算,可以考虑使用赋值表达式避免重复运算。
Python 中的赋值表达式(也称为“海象运算符”,:=)是在 Python 3.8 中引入的,主要作用是在表达式中同时进行赋值和返回值操作,从而简化代码并避免重复计算。
示例如下:
my_list = list(range(1, 6))
print(my_list) # 输出: [1, 2, 3, 4, 5]
# 使用赋值表达式之前,计算i的三次方执行了两次。
# 输出: [27, 64, 125]
print([i ** 3 for i in my_list if i ** 3 > 10])
# 使用赋值表达式之后,计算i的三次方执行了一次。
# 输出: [27, 64, 125]
print([cube for i in my_list if (cube := i ** 3) > 10])