Funkcja enumerate() w języku Python, wyjaśniona przykładami

Ten przewodnik przedstawi Ci działanie funkcji enumerate() w języku Python.

Funkcja enumerate() w Pythonie to elegancki sposób na iterację po elementach sekwencji, jednocześnie mając dostęp do ich pozycji.

Zacznijmy od analizy, jak można pobrać zarówno elementy, jak i ich indeksy za pomocą standardowej pętli. Następnie przejdziemy do zrozumienia składni funkcji enumerate(), prezentując przykłady krok po kroku.

Rozpocznijmy naukę!

Iteracja z użyciem pętli for w Pythonie

W Pythonie, każdy obiekt, który umożliwia przeglądanie jego składowych, nazywamy iterowalnym. Listy, krotki, słowniki i napisy są więc przykładami struktur iterowalnych.

Rozważmy listę zakupów, zdefiniowaną w poniższym fragmencie kodu:

shopping_list = ["owoce", "ciastka", "płatki", "batony proteinowe", "karteczki samoprzylepne"]

W Pythonie pętla for pozwala na przejście po każdym elemencie obiektu iterowalnego. Ogólna postać pętli for wygląda tak:

for element in <obiekt_iterowalny>:
    # operacje na elemencie

# element: zmienna pętli
# <obiekt_iterowalny>: dowolny obiekt iterowalny Pythona: lista, krotka, słownik, napis, itd.

Wykorzystując tę strukturę, przejdźmy teraz przez naszą listę zakupów i wyświetlmy każdy jej składnik.

for element in shopping_list:
  print(element)

# Wynik
owoce
ciastka
płatki
batony proteinowe
karteczki samoprzylepne

Powyższa konstrukcja pozwala na bezpośredni dostęp do poszczególnych elementów. Czasem jednak potrzebujemy również informacji o ich pozycji.

Możemy użyć zmiennej, która będzie przechowywać aktualny indeks i będzie zwiększana wewnątrz pętli, jak widać poniżej:

indeks = 0
for element in shopping_list:
  print(f"indeks:{indeks}, {element}")
  indeks += 1

# Wynik
indeks:0, owoce
indeks:1, ciastka
indeks:2, płatki
indeks:3, batony proteinowe
indeks:4, karteczki samoprzylepne

To rozwiązanie nie jest jednak idealne. Zapomnienie o zwiększeniu indeksu może skutkować błędami w działaniu kodu.

indeks = 0
for element in shopping_list:
  print(f"indeks:{indeks}, {element}")
  # brak aktualizacji indeksu wewnątrz pętli
  # indeks nigdy nie jest zmieniany i zawsze wynosi 0

# Wynik
indeks:0, owoce
indeks:0, ciastka
indeks:0, płatki
indeks:0, batony proteinowe
indeks:0, karteczki samoprzylepne

Innym podejściem jest wykorzystanie pętli for w połączeniu z funkcją range(), co omówimy w kolejnej części.

Wykorzystanie funkcji range() do uzyskania dostępu do indeksów

Wbudowana w Pythona funkcja len() zwraca długość dowolnego obiektu. Możemy zatem użyć len(shopping_list), aby uzyskać długość naszej listy zakupów (w tym przypadku jest to 5).

len(shopping_list)
# Wynik: 5

Funkcja range() generuje sekwencję liczb, którą można wykorzystać w pętli. Przechodząc po sekwencji range(stop), uzyskujemy indeksy 0, 1, 2,…, stop-1.

Ustawiając stop na len(list), uzyskujemy listę poprawnych indeksów. Używając range(), możemy uzyskać dostęp zarówno do indeksu, jak i elementu, jak pokazano poniżej.

for indeks in range(len(shopping_list)):
  print(f"indeks:{indeks}, element: {shopping_list[indeks]}")

# Wynik
indeks:0, element: owoce
indeks:1, element: ciastka
indeks:2, element: płatki
indeks:3, element: batony proteinowe
indeks:4, element: karteczki samoprzylepne

Jednak w Pythonie istnieje bardziej elegancki i zalecany sposób na jednoczesne uzyskiwanie dostępu do indeksów i elementów – funkcja enumerate().

Składnia funkcji enumerate() w Pythonie

Funkcja enumerate() umożliwia dostęp do elementów wraz z ich indeksami za pomocą następującej składni:

enumerate(<obiekt_iterowalny>, start = 0)

W powyższej składni:

  • <obiekt_iterowalny> to wymagany parametr – obiekt iterowalny (lista, krotka, itp.).
  • start to opcjonalny parametr określający, od jakiej wartości ma zacząć się indeksowanie. Domyślnie start wynosi zero.

Wywołując funkcję enumerate() na shopping_list, otrzymujemy obiekt typu enumerate, co prezentuje poniższy kod:

enumerate(shopping_list)
<enumerate at 0x7f91b4240410>

Obiekt typu enumerate nie może być bezpośrednio iterowany. Przekształćmy go zatem w listę:

list(enumerate(shopping_list))

# Wynik
[(0, 'owoce'),
 (1, 'ciastka'),
 (2, 'płatki'),
 (3, 'batony proteinowe'),
 (4, 'karteczki samoprzylepne')]

Kolejnym sposobem na dostęp do elementów obiektu enumerate jest wywołanie funkcji next(), z obiektem enumerate jako argumentem. W Pythonie funkcja next() zwraca kolejny element iteratora.

Funkcja next() w tle wywołuje metodę __next__ iteratora, aby uzyskać kolejne elementy.

Przypiszmy obiekt enumerate do zmiennej shopping_list_enum.

shopping_list_enum = enumerate(shopping_list)

Pierwsze wywołanie next(shopping_list_enum) zwróci indeks zero i element o tym indeksie, czyli krotkę (0, 'owoce').

Wykonując kolejne wywołania funkcji next(), otrzymamy następne elementy wraz z ich indeksami, jak pokazano poniżej.

next(shopping_list_enum)
# (0, 'owoce')
next(shopping_list_enum)
# (1, 'ciastka')
next(shopping_list_enum)
# (2, 'płatki')
next(shopping_list_enum)
# (3, 'batony proteinowe')
next(shopping_list_enum)
# (4, 'karteczki samoprzylepne')

Co się stanie, gdy wywołamy funkcję next() po osiągnięciu końca listy? Otrzymamy błąd StopIteration.

next(shopping_list_enum)
# ---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-16-4220f68f6c7e> in <module>()
----> 1 next(shopping_list_enum)

StopIteration:

Funkcja enumerate() zwraca kolejne indeksy i elementy tylko wtedy, gdy są potrzebne, co jest korzystne z punktu widzenia wydajności. W projektach, w których optymalizacja pamięci jest kluczowa, zaleca się stosowanie enumerate() przy pracy z dużymi sekwencjami iterowalnymi.

Przykłady użycia funkcji enumerate() w Pythonie

Znając już składnię funkcji enumerate(), zmodyfikujmy naszą wcześniejszą pętlę for.

Z poprzedniej sekcji wiemy, że pętla po obiekcie enumerate zwraca krotkę z indeksem i elementem. Możemy tę krotkę rozpakować do dwóch zmiennych: indeks i element.

for indeks, element in enumerate(shopping_list):
  print(f"indeks:{indeks}, element:{element}")

# Wynik
indeks:0, element:owoce
indeks:1, element:ciastka
indeks:2, element:płatki
indeks:3, element:batony proteinowe
indeks:4, element:karteczki samoprzylepne

Sprawdźmy teraz, jak zdefiniować niestandardową wartość startową indeksowania.

Użycie enumerate() z niestandardową wartością startową

Domyślnie indeksowanie w Pythonie zaczyna się od 0. Jeżeli jednak chcemy uzyskać indeksy czytelne dla użytkownika, zaczynające się od 1 lub innej wartości, możemy to łatwo zdefiniować.

W przypadku naszej listy_zakupów, jeśli chcemy, aby indeksy zaczynały się od 1, ustawiamy parametr start na 1.

for indeks, element in enumerate(shopping_list,1):
  print(f"indeks:{indeks}, element:{element}")

# Wynik
indeks:1, element:owoce
indeks:2, element:ciastka
indeks:3, element:płatki
indeks:4, element:batony proteinowe
indeks:5, element:karteczki samoprzylepne

Należy jednak pamiętać, że niestandardowa wartość startowa musi być podana jako drugi argument pozycyjny.

Pomylenie kolejności iterowalnego obiektu i wartości startowej spowoduje błąd, co ilustruje poniższy fragment kodu.

for indeks, element in enumerate(1,shopping_list):
  print(f"indeks:{indeks}, element:{element}")

# Wynik
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-5dbf7e2749aa> in <module>()
----> 1 for indeks, element in enumerate(1,shopping_list):
      2   print(f"indeks:{indeks}, element:{element}")

TypeError: 'list' object cannot be interpreted as an integer

Aby uniknąć takich błędów, możemy określić wartość startową jako argument nazwany, jak pokazano poniżej.

for indeks, element in enumerate(shopping_list, start = 1):
  print(f"indeks:{indeks}, element:{element}")

# Wynik
indeks:1, element:owoce
indeks:2, element:ciastka
indeks:3, element:płatki
indeks:4, element:batony proteinowe
indeks:5, element:karteczki samoprzylepne

Do tej pory nauczyliśmy się używać funkcji enumerate() z listami. Możemy ją także stosować z napisami, słownikami i krotkami.

Użycie enumerate() z krotkami w Pythonie

Załóżmy, że lista_zakupów jest krotką. Krotki, podobnie jak listy, są kolekcjami elementów, jednak są one niemodyfikowalne. Próba modyfikacji krotki spowoduje błąd.

Poniższy kod inicjalizuje shopping_list jako krotkę.

shopping_list = ("owoce", "ciastka", "płatki", "batony proteinowe", "karteczki samoprzylepne")
type(shopping_list)
# Tuple

Próba zmiany pierwszego elementu krotki spowoduje błąd, ponieważ krotki są niemodyfikowalne.

shopping_list[0] = 'warzywa'

# Wynik
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-ffdafa961600> in <module>()
----> 1 shopping_list[0] = 'warzywa'

TypeError: 'tuple' object does not support item assignment

▶ Uruchom poniższy kod, aby zobaczyć, czy funkcja enumerate() działa zgodnie z oczekiwaniami z krotkami.

shopping_list = ("owoce", "ciastka", "płatki", "batony proteinowe", "karteczki samoprzylepne")
for indeks, element in enumerate(shopping_list):
    print(f"indeks:{indeks}, element:{element}")

Wykorzystanie enumerate() z napisami w Pythonie

Funkcję enumerate() w Pythonie możemy także użyć do iteracji po napisach, uzyskując dostęp do znaków i ich indeksów.

Oto przykład:

napis = "Motyl"
for indeks, znak in enumerate(napis):
    print(f"indeks {indeks}: {znak}")

# Wynik
indeks 0: M
indeks 1: o
indeks 2: t
indeks 3: y
indeks 4: l

Jak widać, zostały wydrukowane znaki wraz z ich indeksami (0-4).

Podsumowanie 👩🏽‍💻

Oto kluczowe punkty, które omówiliśmy:

  • Pętla for pozwala na dostęp do elementów oraz na utrzymywanie osobnej zmiennej z indeksem.
  • Funkcja range() pozwala na generowanie sekwencji indeksów, dzięki czemu mamy dostęp do elementów poprzez indeksowanie listy.
  • Zalecanym sposobem w Pythonie jest użycie funkcji enumerate() o składni enumerate(obiekt_iterowalny). Domyślnie indeksowanie zaczyna się od 0.
  • Możemy zdefiniować niestandardową wartość startową, używając składni enumerate(obiekt_iterowalny, start), gdzie start jest początkowym indeksem.
  • Funkcja enumerate może być stosowana do pracy z krotkami, napisami, słownikami i ogólnie z dowolnymi obiektami iterowalnymi.

Mam nadzieję, że ten tutorial był pomocny. W następnej kolejności zachęcam do zapoznania się z tematem wyszukiwania indeksów elementów w listach. Kontynuuj naukę!