Enumerate to jedna z wielu funkcji wbudowanych w Python. Jest bardzo użyteczna ale mimo to wielu początkujących i nawet czasem bardziej zaawansowanych programistów o niej zapomina. Nawet dziś miałem sytuację w której w pracy właśnie enumerate w Python bardzo uprościł nam kod. Jeśli jesteś ciekaw czym właściwie jest enumerate i jak działa, zapraszam do lektury.
We wpisie z poradami do Python na pierwszym miejscu, znalazł się właśnie enumerate. Przypomnę tylko jak prawdopodobnie wygląda twój kod jeśli pisałeś wcześniej w innych językach i dopiero co przesiadłeś się na Python.
countries = ['Polska', 'Niemcy', 'Grecja', 'Szwecja', 'Rosja']
i = 0
for country in countries:
print(i, country)
i += 1
W tym kodzie nie ma nic złego ale jak już używamy języka to korzystajmy z jego pełnego potencjału. I dlatego właśnie warto pamiętać o enumerate, czyli funkcji która pozwala nałożyć indeks na obiekt po którym iterujemy.
Enumerate i lista
Dlatego właśnie prostym zabiegiem można ten kod znacznie uprościć.
countries = ['Polska', 'Niemcy', 'Grecja', 'Szwecja', 'Rosja']
for i, country in enumerate(countries):
print (i, country)
Ten prosty zabieg pozwolił nam skrócić kod sprawiając tym, że jest bardziej " Pythonowowy ". Enumerate można nałożyć na każdy obiekt, po którym można iterować. Od list i tupli, po iteratory i generatory.
Enumerate i tupla
Wyżej pokazałem jak zachowuje się enumerate z listą ale nic nie stoi na przeszkodzie, żeby użyć go również z tuplą. Zobaczmy jak można to zaimplementować
countries = ('Polska', 'Niemcy', 'Grecja', 'Szwecja', 'Rosja')
for i, country in enumerate(countries):
print (i, country)
Enumerate i złożone struktury
Czasem zachodzi potrzeba iterowania po zagnieżdżonych listach lub innych rozbudowanych strukturach. Z tego samego wpisu dotyczącego porad w Python wiemy jak łatwo rozpakować obiekty w Python. Zobaczmy zatem jak można to fajnie połączyć z enumerate. Możemy wypisać zagnieżdżone obiekty jak niżej
persons = [('Dawid', 25), ('Jan', 23), ('Marcin', 22)]
for i, person in enumerate(persons):
print(i, ":", person)
Możemy też rozpakować obiekty i to wszystko połączyć z enumerate. Będzie to wymagać małego zabiegu ale da się
persons = [('Dawid', 25), ('Jan', 23), ('Marcin', 22)]
for i, (name, age) in enumerate(persons):
print(i, ".", name, 'age', age)
Enumerate z generatorem
Jak mowa o iterowalnych obiektach to nie może tu zabraknąć generatorów. Zbudujmy odpowiednik range i sprawdźmy jak się zachowa.
def gen(n):
num = 0
while num < n:
yield num
num += 1
for i, num in enumerate(gen(10)):
print(i, num)
Enumerate z iteratorem
Skoro były generatory, to czas na iterator :)
class IncrementIterator:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.n == self.i:
raise StopIteration
self.i += 1
return self.i
for i, num in enumerate(IncrementIterator(3)):
print(i, num)
Enumerate i string
Zapewne nie jest dla Ciebie nowością, że można iterować po ciągach znaków ale czy wiedziałeś, że na to również można założyć enumerate? Sprawdź jak można to wykorzystać w praktyce
name = 'DDeby'
for i, letter in enumerate(name):
print(letter, 'jest', i, 'literą w tekście', name)
Enumerate z parametrem start
W programowaniu indeksowanie zaczynamy od 0, w życiu natomiast od 1. Na to również jest bardzo prosty sposób, wystarczy bowiem dodać drugi parametr do naszej funkcji. O ile sam enumerate jest jeszcze wykorzystywane o tyle z parametrem start jest już gorzej.
Zobaczymy zatem jak poprawić powyższy kod, żeby wypisywał wyniki w nieco bardziej przystępnej formie
names = ['Dawid', 'Jan', 'Marcin']
for i, name in enumerate(names, start=1):
print(i, '.', name)
Kontekst zimennej
Zastosowanie enumerate ma jeszcze jedną zaletę, mianowicie zmienna "i" jest już zadeklarowana. Co nam to daje? Sporo, bo mając tę zmienną nie musimy ponownie sprawdzać wielkości listy. Łatwiej zrozumiemy to na przykładzie. Jak wypisać podsumowanie bez wykorzystania tego efektu zobaczmy niżej
names = ['Dawid', 'Jan', 'Marcin']
for i, name in enumerate(names, start=1):
print(i, '.', name)
print('Zgłosiło się ', len(names), 'uczestników')
Po co sprawdzać długość listy, skoro wiemy ile przebiegów pętli zrobiliśmy
names = ['Dawid', 'Jan', 'Marcin']
for i, name in enumerate(names, start=1):
print(i, '.', name)
print('Zgłosiło się ', i, 'uczestników')
Na małych listach nie odczujemy różnicy ale przy większych zbiorach lub przy odpytywaniu bazy już jak najbardziej.
Enumerate a pusta lista
W powyższym przykładzie jest jeden haczyk. Ten kod nie zadziała jeśli lista będzie pusta. Nie zadziała, bo jeśli nie będzie obiektów po których można iterować to zmienna do inkrementowania nie będzie zadeklarowana i niżej zostanie wyrzucony wyjątek.
names = []
for i, name in enumerate(names, start=1):
print(i, '.', name)
print('Zgłosiło się ', i, 'uczestników') # NameError: name 'i' is not defined
Podsumowanie
Właśnie poznałeś ciekawe zastosowanie enumerate w Python. Wiesz już jak są zagrożenia i możliwości tej instrukcji.
Jeśli wcześniej nie znałeś takich zastosowań albo znasz kogoś, komu może się przydać, koniecznie podaj ten wpis dalej. A może znasz jakieś inne jego ciekawe zastosowanie? Koniecznie podziel się tym w komentarzu.