(十四)推导式与按需产生数据
1. 从循环得到列表推导式
把达到 30 分钟的记录换算成小时,先使用已经学过的循环:
# 先选出达标记录,再计算小时数并加入结果列表。
minutes = [20, 45, 0, 60]
hours = []
for value in minutes:
if value >= 30:
hours.append(value / 60)
print(hours)输出 [0.75, 1.0]。这里只有一个数据来源、一项筛选和一种结果转换,可以写成列表推导式:
# 仍按“取值、筛选、计算、加入列表”的顺序执行。
minutes = [20, 45, 0, 60]
hours = [value / 60 for value in minutes if value >= 30]
print(hours)虽然结果表达式 value / 60 写在最前面,执行时还是先从 minutes 取出 value,检查后面的条件,再决定是否计算并加入列表。
带 if 的筛选会减少输出项。若希望保留每一项,只替换其中的值,可以把条件表达式放在结果位置:
# 每条输入都产生一条结果,负数替换成 0。
minutes = [20, -5, 30]
cleaned = [value if value >= 0 else 0 for value in minutes]
print(cleaned)这次输出 [20, 0, 30],仍有三项。读推导式时,可以先圈出 for 和尾部筛选,再单独阅读前面的结果表达式。
2. 多层遍历与独立的行
# 两个 for 按从左到右的顺序嵌套:先定 row,再遍历 col。
positions = [(row, col) for row in range(2) for col in range(3)]
print(positions)
# 每轮外层迭代都建立新的行,避免多个位置共享同一行列表。
grid = [[0] * 3 for row in range(2)]
grid[0][1] = 9
print(grid)第一行输出 [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)],矩阵结果是 [[0, 9, 0], [0, 0, 0]]。外层循环每取到一个 row,就重新执行一次内部 [0] * 3,所以两行独立。
集合推导式使用花括号,自动合并重复值;字典推导式在结果位置写 键: 值:
# 集合保存不同的长度,字典保存书名与长度的对应关系。
titles = ["Python", "NumPy", "Flask", "Python"]
lengths = {len(title) for title in titles}
sizes = {title: len(title) for title in titles}
print(lengths == {5, 6})
print(sizes)3. 生成器表达式与消费过程
需要的只是所有平方的和,可以把值逐个交给 sum,不用先建立完整的平方列表:
# 圆括号中的生成器表达式按需产生一个个平方。
squares = (number * number for number in range(1, 4))
print(next(squares))
print(sum(squares))
# 同一生成器已被读完,后续没有剩余项。
print(list(squares))输出 1、13、[]:先取走 1,sum 继续得到 4 和 9。sum(number * number for number in range(1, 4)) 则从头消费,得到 14。生成器表达式与 map 一样保存读取进度,列表推导式则立即建立完整结果列表。
any 检查是否遇到真值,all 检查是否所有值都为真,两者都可以提前停止:
# iter 从列表取得迭代器,随后观察 any 消费到了哪里。
values = iter([0, 1, 2])
print(any(values))
print(list(values))
# 没有找到反例时 all 返回 True;空数据也没有反例。
print(all([]))
print(any([]))any 读取 0 后继续,读取 1 后已经确定结果为 True,所以剩下 [2]。没有元素时,all 得到 True,any 得到 False。数据流究竟被读到哪里,可以用同一个迭代器继续取值来观察。推导式与生成器相关示例