第 21 课 · 进阶 · 18 分钟

Python enumerate 与 zip

不用手写计数器,也能拿到位置并并行遍历序列。

enumeratezip循环索引并行列表

小票要行号,价目表要把商品和价格配成对。两个都是循环,里面都藏着一个计数器。哪个内置函数能把这份记账活接过去?

两个小工具能省掉大量循环里的杂活。enumerate 会给每个元素一个位置,zip 则让两个或多个序列并排前进。它们返回的都是迭代器,想直接查看结果时记得用 list() 包起来。 你还会发现 zip 的静默截断、用 enumerate 遍历惰性迭代器,并用 zip(*rows) 转置行。

不用手写计数器

enumerate(colors) 每轮产生一对值:索引和元素。直接在 for 语句里解包这一对即可。它比单独维护一个计数器再手动加一更清楚。

colors = ["red", "green", "blue"]
for index, color in enumerate(colors):
    print(index, color)

索引和元素一起拿到

从 1 开始编号

start 参数只改变第一个编号,不会改变原序列。面向人的步骤或排行榜可以从 start=1 开始。原列表本身不会被修改。

for number, color in enumerate(["red", "green"], start=1):
    print(f"{number}: {color}")

更适合展示的编号

并行遍历两个列表

zip 会在最短的输入结束时停止。数据本来就该一一对应时这很方便,但长度不一致时也可能掩盖缺失值。需要计数或把配对当成元组打印时,可以先转成列表。

names = ["Ada", "Grace"]
scores = [92, 88]
for name, score in zip(names, scores):
    print(f"{name}: {score}")
print(list(zip([1, 2], ["a", "b"])))

并行序列

zip 会静默停止,strict 会报错

zip 在最短输入处停止。数据本来一一对应时很方便,缺失一条记录时却会悄悄丢数据。strict=True 会把长度不一致变成 ValueError,而不是截断。在两边本应等长的边界上使用它。

names = ["Ada", "Grace", "Lin"]
scores = [92, 88]
print(list(zip(names, scores)))
try:
    print(list(zip(names, scores, strict=True)))
except ValueError as error:
    print(type(error).__name__, error)

静默截断与明确失败

enumerate 适用于任何迭代器

enumerate 不需要 len() 或下标。它取一个元素,产出一对值,因此生成器、文件和数据库游标都能用。需要位置时用它;不要为了计数先把大序列全部装进列表。

def readings():
    yield 4.5
    yield 3.0
    yield 5.25

for position, value in enumerate(readings(), start=1):
    print(position, value)

给惰性流编号

用 zip(*rows) 转置行

zip(*rows) 把一组行变成列。它是把名称和价格分开的紧凑写法,但每一行的宽度必须相同。结果是由元组组成的迭代器;需要查看完整形状时再转换。

rows = [("latte", 4.5), ("tea", 3.0), ("mocha", 5.0)]
names, prices = zip(*rows)
print(names)
print(prices)
print(sum(prices))

行进去,列出来

本课要点

  • enumerate 产生 (索引, 元素) 对。
  • 编号要展示给人看时,用 start=1。
  • zip 并行遍历序列,并在最短的序列处停止。
  • 这两个函数返回迭代器,不是列表。
  • zip 在最短输入处静默停止;strict=True 让长度不一致显式失败。

常见错误

  • 不转成列表就直接对 enumerate 的结果做下标访问。
  • 以为 zip 会用 None 补齐较短的输入;它其实会停止。
  • enumerate 已经能表达意图,却仍然手写计数器。
  • 假设输入等长,结果丢掉了较长序列的尾部。
轮到你

给 ['Ada', 'Grace'] 打印从 1 开始的编号,再打印 list(zip([1, 2], ['a', 'b']))。

动手试试

改改变量、先预测输出,再运行代码。第一次点击“运行代码”时会下载 Python 运行时,可能需要几秒钟。

浏览器内 Python本地运行 · 无需账号
首次运行会从 CDN 下载 Pyodide。修改后点击“运行代码”。

练习本课

12 道题,作答后立即看到解释。

查看 12 道题答案开始练习
← 正则表达式pathlib 路径 →