Python enumerate 用于索引和值对

Python enumerate 会给可迭代对象添加一个递增索引,在遍历时返回 (索引, 值) 对。 当你需要每个元素的位置(例如编号输出或标签)时使用它。 这是将元素与其位置配对的内置模式,适用于列表、生成器或文件行。

Python Enumerate 示例:编号输出

输出:

输出将显示在这里...

输出:

1. 发货
2. 给客户发邮件

示例解析

  1. enumerate(tasks, start=1) 将每个任务与其位置配对。
  2. start=1 让编号更符合人类阅读习惯。
  3. 输出展示了每个任务的编号。

Python enumerate 常见坑

错误 1:忘记编号从 0 开始。

for line_no, row in enumerate(rows):
    print(f"第 {line_no} 行: {row['sku']}")
for line_no, row in enumerate(rows, start=1):
    print(f"第 {line_no} 行: {row['sku']}")

原因:enumerate 默认从 0 开始,这对索引是正确的,但对面向用户的行号会造成混淆。

错误 2:枚举字典却以为得到的是值。

region_totals = {"西部": 1200, "东部": 980}
for i, total in enumerate(region_totals):
    print(i, total)
region_totals = {"西部": 1200, "东部": 980}
for i, (region, total) in enumerate(region_totals.items(), start=1):
    print(i, region, total)

原因:遍历 dict 得到的是键,因此 enumerate 会将索引与键配对,除非你遍历 .items()。 如果你需要键/值查找模式,请看 Python dict 示例

错误 3:为大数据构建 list(enumerate(...))

indexed_rows = list(enumerate(rows, start=1))
for line_no, row in indexed_rows:
    print(line_no, row)
for line_no, row in enumerate(rows, start=1):
    print(line_no, row)

原因:list() 会把所有对加载进内存,而 enumerate 本身是惰性的,可以流式处理。

enumerate vs range(len()):怎么选

使用 enumerate 当…使用 range(len()) 当…
你需要索引和元素一起使用。你只需要数字索引。
你遍历任意可迭代对象,包括生成器。你需要按自定义步长跳跃或只按索引遍历。
你希望循环更清晰、无需手动索引。你需要索引用于切片或随机访问。

经验法则:需要索引+值时用 enumerate;索引本身是重点时用 range(len())。 如果你只需要索引运算,请看更深入的 Python range 示例

性能考虑

enumerate 是 O(n) 且惰性的,因此除非用 list() 包裹,否则不会额外分配成对列表。实际使用中,它比在循环内调用 list.index() 更快更清晰(后者可能让循环变成 O(n^2))。如果你只是给行加编号,enumerate 能保持常量内存同时提供行号。

Enumerate 的其他用法

扫描日志时标记错误行。

lines = [
    "INFO 已连接",
    "错误 超时",
    "INFO 重试",
]

for line_no, line in enumerate(lines, start=1):
    if "错误" in line:
        print(f"第 {line_no} 行: {line}")

这样可以保留精确行号,便于调试和事故复盘。 它同样适用于文件,因为 enumerate 接受任何可迭代对象。

按索引原地规范化列表。

names = ["  ada", "grace ", "  linus"]
for i, name in enumerate(names):
    # 需要原地修改列表时按索引更新
    names[i] = name.strip().title()

print(names)

这样数据仍在同一个列表中,同时你拥有用于回写的索引。 比手动计数更清晰,也让循环保持可读性。