Python Cookbook-4.4 循环访问序列中的元素和索引
任务
需要循环访问一个序列,并且每一步都需要知道已经访问到的索引(因为需要重新绑定序列的入口),但 Python 提供的首选的循环方式完全不用依赖索引。
解决方案
内建函数 enumerate 正是为此而生。看例子:
for index,item in enumerate(sequence):
if item > 23:
sequence[index] = transform(item)
它看上去很干净易读,而且比那种通过索引访问元素的方式快:
for index in range(len(sequence)):
if sequence[index] > 23:
sequence[index] = transform(sequence[index])
讨论
循环遍历一个序列是很常见的需求,Python强烈建议你用一种最直接的方式。事实上这也是最具有Python 风格的访间序列中每个元素的方式:
for item in sequence:
process(item)
而其他一些典型的比较底层的语言,不是用这种直接的循环方式,而是通过序列的索引,根据索引找到每一个对应的子项:
for index in range(len(sequence)):
process(sequence[index])
直接的循环方式更加干净、更易读、更快,而且也更通用(因为根据定义,此法可以应用于任何可迭代对象,而根据索引访问的方式则只适用于序列,如列表)。但是,有时候在循环中,你的确需要同时获得索引和索引对应的子项。一个常见的理由是,你想重新绑定列表的新入口,必须将thelist[index]赋值为一个新的子项。为了支持这种需求,Python 提供了内建函数 enumerate,它接受任何可迭代的参数,并返回一个迭代器,迭代器产生的是一个(两个子项的元组)形如(index,item)的结果,一次一项。因此你的 for 子句的头部可以写成:
for index,item in enumerate(sequence):
这样,在for的主体中,索引和子项都是可以访问的。
为了帮助你记忆 enumerate 产生的结果,考虑惯用法d=dict(enumerate(L))。实际上从某种意义上来讲,用此法获得的字典d是等价于列表L的,因为对于任意一个有效的非负索引i,d[i] is L[i]都成立。