Python推导式功能:一行代码搞定复杂逻辑
对话实录
小白:(抓狂)我写了 10 行循环,同事用 1 行就搞定了!
专家:(掏出魔杖)掌握推导式,代码瞬间瘦身!
三大推导式
1. 列表推导式
传统写法需要先创建一个空列表,然后通过循环逐个计算并添加元素。
# 传统写法
squares = []
for x in range(5):
squares.append(x**2)
而使用列表推导式,只需一行代码就能完成相同功能。
它的结构是[表达式 for 变量 in 可迭代对象] 或者 [表达式 for 变量 in 可迭代对象 if 条件表达式] 或者 [表达式A if 条件表达式 else 表达式B for 变量 in 可迭代对象]
# 推导式写法
squares = [x**2 for x in range(5)] # → [0,1,4,9,16]
squares = [x**2 for x in range(5) if x%2==0] # → [0,4,16]
squares = [x**2 if x%2==0 else x**3 for x in range(5) ] # → [0,1,4,27,16]
专家提醒:推导式比map+lambda更 Pythonic!map结合lambda也能实现类似功能,但代码相对更复杂,不够简洁直观,比如list(map(lambda x: x**2, range(5)))。
2. 字典推导式
传统方式构建字典,需要先初始化一个空字典,再通过循环逐个添加键值对。
# 传统写法
dict1 = {}
for x in range(5):
dict1[x] = x**2
字典推导式的结构是{键表达式: 值表达式 for 变量 in 可迭代对象} 或者 {键表达式: 值表达式 for 变量 in 可迭代对象 if 条件表达式} 或者 {键表达式: 值表达式 if 条件表达式 else 值表达式 for 变量 in 可迭代对象},可以快速生成字典。
# 推导式写法
dict1 = {x: x**2 for x in range(5)} # → {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
dict2 = {x: x**2 for x in range(5) if x%2==0} # → {0:0,2:4,4:16}
dict3 = {x: x**2 if x%2==0 else x**3 for x in range(5)} # → {0: 0, 1: 1, 2: 4, 3: 27, 4: 16}
3. 集合推导式
传统方式构建集合,需要先初始化一个空集合,再通过循环逐个添加值。
# 传统写法
set1 = set()
# 不能用set1={} 这是定义一个空字典
for x in range(5):
set1.add(x**2) #-> {0, 1, 4, 9, 16}
集合推导式的结构是{表达式 for 变量 in 可迭代对象} 或者 {表达式 for 变量 in 可迭代对象 if 条件表达式} 或者 {表达式A if 条件表达式 else 表达式B for 变量 in 可迭代对象},可以快速生成集合。
# 推导式写法
set1 = {x**2 for x in range(5)} # → {0, 1, 4, 9, 16}
set2 = {x**2 for x in range(5) if x%2==0} # → {0, 4, 16}
set3 = {x**2 if x%2==0 else x**3 for x in range(5)} # → {0, 1, 4, 16, 27}
四大实战案例
案例 1:多重条件过滤
# 多重条件
nums = [x for x in range(20) if x%2==0 if x>10] # → [12,14,16,18]
案例 2:嵌套推导式
对于矩阵转置,传统方法较为复杂,需要嵌套循环。而嵌套推导式通过两层循环实现转置。外层循环遍历列索引,内层循环遍历行,根据行列索引获取元素组成新的矩阵。
# 矩阵转置
matrix = [[1,2,3],[4,5,6],[7,8,9]]
transposed = [[row[i] for row in matrix] for i in range(3)]
# → [[1,4,7],[2,5,8],[3,6,9]]
案例 3:字典键值互换
传统方法需遍历字典,逐个交换键值对创建新字典。字典推导式则简洁很多,使用items()方法获取键值对,然后交换位置生成新字典。
data = {"a":1, "b":2, "c":3}
inverted = {v:k for k,v in data.items()} # → {1:"a",2:"b",3:"c"}
案例4:嵌套解包
在二维列表展开时,传统方法需要嵌套循环遍历。嵌套解包的推导式可以简洁地将二维列表扁平化。先遍历外层列表,再遍历内层列表,将元素逐个取出组成新列表。
# 二维列表展开
matrix = [[1,2],[3,4]]
flat = [x for row in matrix for x in row] # → [1,2,3,4]
三大血泪陷阱
过度嵌套
过度嵌套的推导式虽然代码简洁,但可读性极差,维护困难。
# 难以阅读的写法
result = [[x*y for y in range(10)] for x in range(10)]
建议拆分成更易读的形式,先创建外层列表,再在内层使用推导式填充。
# 建议拆分
rows = []
for x in range(10):
row = [x*y for y in range(10)]
rows.append(row)
副作用问题
推导式中对原列表进行修改会产生副作用,改变原数据结构,这通常不是我们期望的。
# 错误示范
[x.append(1) for x in [[], [], []]] # 修改了原列表!
正确做法是创建新列表,通过连接操作实现类似效果,不会影响原列表。
# 正确做法
new_lists = [x + [1] for x in [[], [], []]]
性能陷阱
错误的写法会导致性能问题,比如在大范围内进行不必要的查找判断。
# 错误示范
[x for x in range(10**6) if x in set(range(0,10**6,2))] # 慢!
应直接使用步长来生成符合条件的序列,避免不必要的集合操作,提升性能。
# 正确做法
[x for x in range(0,10**6,2)]
专家工具箱
1.生成器表达式
生成器表达式和列表推导式语法相似,只是把方括号换成圆括号。它不会一次性生成所有元素,而是按需生成,节省内存,适合处理大规模数据。使用next()函数可以逐个获取元素。
# 节省内存
squares = (x**2 for x in range(10**6))
print(next(squares)) # → 0
小白:(献上膝盖)原来推导式这么强大!
专家:(扶起小白)记住:推导式是 Python 的语法糖,但别贪吃哦!