如何在 Python 的 foreach 循环中访问索引

通常,当你遍历 Python 中的元素集合,比如列表,时,你还需要与每个元素相关联的序号。这样的数字通常称为索引 - index

在执行 foreach 循环时访问索引的 pythonic 方法是使用内置函数 enumerate()

enumerate() 向可迭代集合中的每个元素添加索引。然后,你可以使用 list() 内置函数来获取元组列表。

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names))
[(0, 'Bob'), (1, 'Alice'), (2, 'John'), (3, 'Cindy')]

注意,Python 索引是从 0 开始的。但是,如果你希望索引从 1 开始(例如,在打印报告数据时),则可以通过向 enumerate 传递一个附加 start 参数来轻松实现索引 enumerate

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names), start=1)
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]

如果你要打印来自不同数据源的数据但希望所有数据项之间的索引一致,则上述指定启示索引的方法很有用。

>>> data_source1 = ['Bob', 'Alice', 'John', 'Cindy']
>>> data_source2 = ['Sarah', 'Jeff', 'Emily', 'Adam']
>>> list(enumerate(data_source1, start=1))
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]
>>> list(enumerate(data_source2, start=len(data_source1) + 1))
[(5, 'Sarah'), (6, 'Jeff'), (7, 'Emily'), (8, 'Adam')]

请注意,你不必将 Enumerate 对象转换为列表。它本身是可迭代的,因此可以直接对其进行迭代。

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> for idx, name in enumerate(names):
...   print(name)
...
Bob
Alice
John
Cindy

迭代元素集合时,可能还有其他方法可以保留索引,但是使用 enumerate() 被认为是规范的,是首选方法。

另一种选择是使用单独的索引变量,手动对其进行初始化,并在每次迭代时对其进行手动递增。但是,这种方法是重新造轮子,不被推荐使用。

这是 PEP 279的引言,其中引入了 enumerate() 函数。

This PEP introduces a new built-in function, enumerate() to simplify a commonly used looping idiom. It provides all iterable collections with the same advantage that iteritems() affords to dictionaries – a compact, readable, reliable index notation.

你可能会问在代码中使用 enumerate 是否会对性能产生影响。你可以自己做一下性能测试,但是请记住,enumerate 是在 for-each 循环中访问可迭代索引的一种惯用方式。Python 维护人员建议使用惯用代码,他们将尽一切努力使其高效运行。

以下是上述 PEP 中的 enumerate() 可能实现的方式。

def enumerate(collection):
   'Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...'
   i = 0
   it = iter(collection)
   while 1:
       yield (i, it.next())
       i += 1
comments powered by Disqus