如何在 Python 的 foreach 迴圈中訪問索引

Aliaksei Yursha 2020年6月25日
如何在 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

相關文章 - Python Loop