Cursus

In deze tutorial bespreken we wat de functie enumerate() in Python is, wanneer je die gebruikt, wat voor objecten hij aanmaakt, welke syntax hij heeft en hoe hij werkt. Daarna bekijken we voorbeelden van het enumereren van verschillende typen objecten in Python, de alternatieven voor de functie enumerate(), en waarom die minder geschikt zijn voor dezelfde taak.
Wat is enumerate in Python en wanneer gebruik je het?
De functie enumerate() is een ingebouwde Python-functie die een iterable neemt (een verzameling items of elk ander Python-object dat iteratie ondersteunt, zoals tuples, lijsten, sets of strings), onder water door de items itereert en een enumerate-object retourneert. Met andere woorden: deze functie kent aan elk item van een iterable een teller toe die met 1 oploopt en helpt ons om iteraties bij te houden terwijl we door dat object loopen. Nadat we een enumerate-object hebben gemaakt, kunnen we het omzetten naar een lijst, een tuple of een dictionary (respectievelijk met de functies list(), tuple() of dict()), of er direct doorheen loopen om zowel de items als hun bijbehorende indexen te benaderen.
Het gebruik van de functie enumerate() is handig vanuit het oogpunt van geheugen- en rekenefficiëntie in vergelijking met for-loops, omdat hij in één keer de index én het bijbehorende item teruggeeft.
Syntax
De syntax van de functie enumerate() is heel eenvoudig:
enumerate(iterable, start=0)
Hier is iterable een iterable object dat we willen enumereren, en start is een optionele parameter die de startindex van de teller definieert (standaard is dit de gebruikelijke Python-indexering die bij 0 begint).
Let op: het toepassen van de functie enumerate() op een iterable verandert het oorspronkelijke object niet. In plaats daarvan moet je het resulterende enumerate-object aan een variabele toewijzen als je het later nog wilt gebruiken.
Nu gaan we bekijken hoe deze functie werkt op verschillende soorten Python-iterables.
Een lijst enumereren
Eerst passen we de functie enumerate() toe op een Python-lijst:
drinks = ['tea', 'coffee', 'cappuccino', 'lemonade']
enumerated_drinks = enumerate(drinks)
print(type(enumerated_drinks))
print(enumerated_drinks)
Output:
<class 'enumerate'>
<enumerate object at 0x000002DC3A1145C0>
Het type van het resulterende object is enumerate, en toen we het probeerden te printen, bevestigden we opnieuw het objecttype en waar het in het computergeheugen is opgeslagen. Laten we proberen het eerste element van dit object te benaderen op dezelfde manier als we met een Python-lijst of -tuple zouden doen:
print(enumerated_drinks[0])
Output:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5948/1233607596.py in <module>
----> 1 print(enumerated_drinks[0])
TypeError: 'enumerate' object is not subscriptable
We kregen een foutmelding die aangeeft dat de onderdelen van een enumerate-object niet op deze manier toegankelijk zijn. In plaats daarvan moeten we het voor dit doel omzetten naar een lijst, een tuple of een dictionary, of direct door het enumerate-object loopen. Laten we ons enumerate-object omzetten naar een lijst:
list_enumerated_drinks = list(enumerated_drinks)
print(list_enumerated_drinks)
Output:
[(0, 'tea'), (1, 'coffee'), (2, 'cappuccino'), (3, 'lemonade')]
Nu zien we duidelijk de binnenstructuur van de resulterende lijst: elk item is een tuple van 2 elementen, waarbij het eerste element de index is van het overeenkomstige item in de oorspronkelijke lijst en het tweede het item zelf is. We kunnen een gebruikelijke indexeringsaanpak gebruiken om de elementen van deze lijst te benaderen:
print(list_enumerated_drinks[0])
print(list_enumerated_drinks[0][1])
Output:
(0, 'tea')
tea
Laten we nu proberen een enumerate-object dat uit de oorspronkelijke lijst is gemaakt om te zetten in een tuple. Bovendien stellen we dit keer de optionele parameter start in op 1:
tuple_enumerated_drinks = tuple(enumerate(drinks, start=1))
print(tuple_enumerated_drinks)
Output:
((1, 'tea'), (2, 'coffee'), (3, 'cappuccino'), (4, 'lemonade'))
De binnenstructuur van de bovenstaande tuple is identiek aan die van de eerder gemaakte lijst. Dit keer hebben we echter de telling aangepast zodat die meer "mensenstijl" is in plaats van Python-indexering die bij 0 begint.
Er is één interessante methode van een enumerate-object die het vermelden waard is: de methode next(). Laten we het object enumerated_drinks opnieuw maken en deze methode in actie zien:
enumerated_drinks = enumerate(drinks)
print(next(enumerated_drinks))
print(next(enumerated_drinks))
print(next(enumerated_drinks))
print(next(enumerated_drinks))
print(next(enumerated_drinks))
Output:
(0, 'tea')
(1, 'coffee')
(2, 'cappuccino')
(3, 'lemonade')
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5948/330134057.py in <module>
4 print(next(enumerated_drinks))
5 print(next(enumerated_drinks))
----> 6 print(next(enumerated_drinks))
StopIteration:
Zoals we zien, geeft elke aanroep van deze methode op een enumerate-object het volgende item terug (en we kunnen opnieuw bevestigen dat elk item een tuple van 2 elementen is met het bijbehorende paar teller-item). Wanneer alle items op zijn, raakt het enumerate-object uitgeput en resulteert een poging om de methode next() aan te roepen in een StopIteration-fout. Inderdaad, als we nu proberen dit enumerate-object om te zetten naar een lijst, zien we dat die leeg is
print(list(enumerated_drinks))
Output:
[]
Dit betekent dat bij elke toepassing van de methode next() op een enumerate-object er een item uit het object wordt gehaald, waardoor het object telkens kleiner wordt tot het volledig uitgeput is. We zullen deze eigenschap van enumerate-objecten later ook zien wanneer we for-loops erop toepassen.
Als je meer wilt leren over Python-lijsten en andere basisconcepten van Python, kun je de DataCamp-cursus Introduction to Python volgen.
Een tuple enumereren
Het toepassen van de functie enumerate() op een tuple is identiek aan die op een lijst:
drinks = ('tea', 'coffee', 'cappuccino', 'lemonade')
enumerated_drinks = enumerate(drinks)
print(enumerated_drinks)
Output:
<enumerate object at 0x000002DC3A098D40>
We hebben opnieuw een enumerate-object verkregen waarvan de items niet toegankelijk zijn met de gebruikelijke Python-indexering. Laten we dit object omzetten in een ander object, dit keer in een dictionary:
dict_enumerated_drinks = dict(enumerated_drinks)
print(dict_enumerated_drinks)
Output:
{0: 'tea', 1: 'coffee', 2: 'cappuccino', 3: 'lemonade'}
Elk key:value-paar van de resulterende dictionary vertegenwoordigt het bijbehorende paar teller-item. We kunnen de waarden van de dictionary op de gebruikelijke Python-manier benaderen:
print(dict_enumerated_drinks[0])
print(dict_enumerated_drinks[3])
Output:
tea
lemonade
Als je dieper wilt duiken in Python-dictionaries en pandas, bekijk dan de cursus Intermediate Python.
Een string enumereren
Aangezien Python-strings reeksen van tekens zijn en dus ook iterable objecten, kunnen we ook een enumerate-object voor een string aanmaken:
enumerated_hello_world = enumerate('Hello, World!', start=10)
print(enumerated_hello_world)
Output:
<enumerate object at 0x000002DC3A145C40>
Zoals we eerder deden, zetten we dit object om naar een lijst:
list_enumerated_hello_world = list(enumerated_hello_world)
print(list_enumerated_hello_world)
Output:
[(10, 'H'), (11, 'e'), (12, 'l'), (13, 'l'), (14, 'o'), (15, ','), (16, ' '), (17, 'W'), (18, 'o'), (19, 'r'), (20, 'l'), (21, 'd'), (22, '!')]
We zien de inmiddels bekende tuples van 2 elementen, waarbij het eerste element de telling is van het overeenkomstige teken van de string (in dit geval beginnend bij 10) en het tweede het teken zelf. De spatie en leestekens worden ook meegeteld.
Laten we het object enumerated_hello_world opnieuw maken, dit keer zonder start=10, en de methode next erop toepassen:
enumerated_hello_world = enumerate('Hello, World!')
print(next(enumerated_hello_world))
print(next(enumerated_hello_world))
print(next(enumerated_hello_world))
print(next(enumerated_hello_world))
print(next(enumerated_hello_world))
print(next(enumerated_hello_world))
# Creating a list from the remaining enumerate object
print(list(enumerated_hello_world))
Output:
(0, 'H')
(1, 'e')
(2, 'l')
(3, 'l')
(4, 'o')
(5, ',')
[(6, ' '), (7, 'W'), (8, 'o'), (9, 'r'), (10, 'l'), (11, 'd'), (12, '!')]
In de laatste regel van het bovenstaande codeblok stopten we met het toepassen van de methode next() en zetten we het object enumerated_hello_world om naar een lijst. De resulterende lijst bevat de overgebleven tekens van het oorspronkelijke enumerate-object nadat de methode next() er meerdere keren op is toegepast.
Enumereren met een for-loop
Tot slot bekijken we hoe de functie enumerate() werkt in combinatie met een for-loop:
for item in enumerate(['tea', 'coffee', 'cappuccino', 'lemonade']):
print(item)
Output:
(0, 'tea')
(1, 'coffee')
(2, 'cappuccino')
(3, 'lemonade')
Bij elke iteratie wordt de bijbehorende tuple teller-item teruggegeven, net zoals gebeurt wanneer we de methode next() gebruiken. Ook al is het niet meteen zichtbaar in het bovenstaande codeblok, het enumerate-object verliest zijn items (d.w.z. de 2-elementtuples) ook één voor één bij elke iteratie. Om dit te laten zien, herschrijven we het bovenstaande codeblok in een andere vorm en controleren we de lengte van de resulterende lijst na afloop van alle iteraties:
drinks = ['tea', 'coffee', 'cappuccino', 'lemonade']
enumerated_drinks = enumerate(drinks)
for item in enumerated_drinks:
print(item)
print(list(enumerated_drinks))
Output:
(0, 'tea')
(1, 'coffee')
(2, 'cappuccino')
(3, 'lemonade')
[]
Net als bij het toepassen van de methode next() put itereren door een enumerate-object het geleidelijk uit.
Laten we echter teruggaan naar het vorige codeblok. Hoe kunnen we elk element afzonderlijk uit elke 2-elementtuple benaderen? Hiervoor voegen we nog een iteratievariabele toe en pakken we de tuples uit:
for count, drink in enumerate(['tea', 'coffee', 'cappuccino', 'lemonade']):
print(count, drink)
Output:
0 tea
1 coffee
2 cappuccino
3 lemonade
Hierboven gaven we twee variabelen terug voor elke tuple: één voor de telling van het item en één voor het item zelf.
Let op: we kunnen dezelfde operatie als hierboven ook implementeren zonder de functie enumerate() te gebruiken. We kunnen bijvoorbeeld een teller-variabele buiten de loop introduceren en deze bij elke iteratie van de loop met 1 verhogen:
count = 0
for drink in ['tea', 'coffee', 'cappuccino', 'lemonade']:
print(count, drink)
count += 1
Output:
0 tea
1 coffee
2 cappuccino
3 lemonade
Als alternatief kunnen we een combinatie gebruiken van de functies range() en len() op een vooraf gedefinieerde lijst (of een tuple, een string, enz.):
drinks = ['tea', 'coffee', 'cappuccino', 'lemonade']
for count in range(len(drinks)):
print(count, drinks[count])
Output:
0 tea
1 coffee
2 cappuccino
3 lemonade
Bovendien kunnen we in beide alternatieven voor de functie enumerate() de teller-variabele nog steeds aanpassen zodat die niet bij nul begint:
count = 1
for drink in ['tea', 'coffee', 'cappuccino', 'lemonade']:
print(count, drink)
count += 1
print('\n')
drinks = ['tea', 'coffee', 'cappuccino', 'lemonade']
for count in range(len(drinks)):
print(count + 1, drinks[count])
Output:
1 tea
2 coffee
3 cappuccino
4 lemonade
1 tea
2 coffee
3 cappuccino
4 lemonade
In vergelijking met het gebruik van de functie enumerate() zijn beide bovenstaande benaderingen echter omslachtiger, foutgevoeliger (bijv. we kunnen vergeten de teller bij elke iteratie handmatig bij te werken) en vergen ze meer code. Daarom is het gebruik van de functie enumerate() de meest Pythonic aanpak wanneer we bij elke iteratie zowel de telling als het item van een iterable nodig hebben.
Conclusie
In deze tutorial hebben we veel geleerd over de functie enumerate() in Python, waaronder de vele toepassingen, mogelijke alternatieven en waarom die uiteindelijk minder effectief zijn dan enumerate(). De functie enumerate() zal voor de meeste beginnende Python-gebruikers niet bekend zijn, en zelfs gevorderde programmeurs zijn soms niet op de hoogte van deze enorm handige functie.
Wil je meer leren over enumerate()? Bekijk dan de cursus Python Data Science Toolbox (Part 2), die iterators en iterables in detail behandelt en interactieve oefeningen biedt om nieuwe skills te oefenen. Daarnaast, als je andere Python-concepten wilt beheersen, is Learn Python with DataCamp misschien interessant: dit biedt diverse skill- en carrièretracks, cheatsheets, tutorials, Python-certificeringen en toetsingen.
