Historia pytania
Funkcja enumerate() powstała w Pythonie, aby ułatwić i idiomatyczne iterowanie (przechodzenie) przez elementy sekwencji z jednoczesnym uzyskaniem bieżącego indeksu. Jest to szczególnie istotne, ponieważ wcześniej często zalecano ręczne prowadzenie osobnego licznika, co uważano za mniej idiomatyczne i mniej czytelne.
Problem
W pętlach często trzeba znać nie tylko bieżącą wartość, ale także jej indeks w sekwencji. Ręczne zarządzanie indeksami za pomocą osobnej zmiennej (i) i wywołania range(len(seq)) prowadzi do błędów (rozbieżność indeksów i wartości, duplikacja kodu) i pogarsza czytelność.
Rozwiązanie
enumerate() zwraca leniwy iterator, który na każdym kroku zwraca krotkę (indeks, wartość) bieżącego elementu. Dzięki niej można elegancko i niezawodnie pracować z indeksami:
kolory = ['czerwony', 'zielony', 'niebieski'] for idx, kolor in enumerate(kolory): print(idx, kolor)
Iteracja zaczyna się od zera, ale można podać dowolną wartość początkową:
for idx, kolor in enumerate(kolory, start=1): print(idx, kolor)
Kluczowe cechy:
enumerate() działa z każdą iterowalną sekwencją, zwraca krotkę (indeks, element)start, co bywa wygodneCzy można wyłączyć zwracanie indeksu i pozostawić tylko wartości przy pracy z enumerate()?
Nie, enumerate() zawsze zwraca pary (indeks, wartość). Jeśli potrzebujesz tylko wartości, użyj zwykłej pętli for:
for wartość in moja_lista: print(wartość)
Czy można używać enumerate() z obiektami nieindeksowymi, takimi jak generatory?
Tak, enumerate() działa z każdym obiektem iterowalnym, w tym z generatorami. Indeksacja będzie odbywać się w kolejności pojawiania się wartości:
def mojgen(): for i in range(3): yield chr(ord('a')+i) for idx, val in enumerate(mojgen()): print(idx, val) # 0 a, 1 b, 2 c
Czy można automatycznie ustawić początkowy indeks różny od 0, a co się stanie przy ujemnych wartościach?
Tak, enumerate() ma argument start. Jeśli przekazać wartość ujemną — indeksacja zacznie się od tej wartości:
for idx, x in enumerate(['a', 'b', 'c'], start=-3): print(idx, x) # -3 a, -2 b, -1 c
range(len(seq)) zamiast enumerate() do przeszukiwania listy — sprawia, że kod staje się mniej oceniany/idiomatycznyW zespole utrzymującym dużą bazę kodu, często używają:
for i in range(len(moja_lista)): proces(i, moja_lista[i])
Plusy:
Minusy:
Po refaktoryzacji przechodzą na:
for idx, val in enumerate(moja_lista): proces(idx, val)
Plusy:
Minusy: