问题的历史
enumerate() 函数在 Python 中出现,是为了方便和符合语法习惯地遍历(迭代)序列的元素,同时获取当前的索引。这一点特别重要,因为在此之前,通常建议手动维护一个单独的计数器,这被认为是不符合语法习惯和阅读性差。
问题
在循环中,常常需要知道当前值及其在序列中的索引。通过单独变量 (i) 和调用 range(len(seq)) 来手动管理索引,会导致错误(索引与值不一致,代码重复)并降低可读性。
解决方案
enumerate() 返回一个惰性迭代器,在每一步返回当前元素的元组 (索引, 值)。使用它可以优雅且可靠地处理索引:
colors = ['red', 'green', 'blue'] for idx, color in enumerate(colors): print(idx, color)
迭代从零开始,但您可以指定任何起始值:
for idx, color in enumerate(colors, start=1): print(idx, color)
关键特性:
enumerate() 可以与任何可迭代序列一起使用,返回元组 (索引, 元素)start,这有时很方便在使用 enumerate() 时,可以关闭返回索引,仅保留值吗?
不可以,enumerate() 始终返回 (索引, 值) 的元组。如果只需要值,可以使用普通的 for 循环:
for value in my_list: print(value)
可以将 enumerate() 用于不可索引的对象,例如生成器吗?
可以,enumerate() 与任何可迭代对象都能正常工作,包括生成器。索引将按值出现的顺序进行:
def mygen(): for i in range(3): yield chr(ord('a')+i) for idx, val in enumerate(mygen()): print(idx, val) # 0 a, 1 b, 2 c
可以自动指定一个不是 0 的起始索引吗?负值会怎样?
可以,enumerate() 有一个 start 参数。如果传递一个负值——索引将从该值开始:
for idx, x in enumerate(['a', 'b', 'c'], start=-3): print(idx, x) # -3 a, -2 b, -1 c
range(len(seq)) 替代 enumerate() 遍历列表 — 这样代码会变得不太符合语法习惯在团队中维护大量代码时,常常使用:
for i in range(len(mylist)): process(i, mylist[i])
优点:
缺点:
经过重构,转向:
for idx, val in enumerate(mylist): process(idx, val)
优点:
缺点: