Werken met dicts
Inleiding
Woordenboeken zijn een veelgebruikte type collectie binnen Python. In eerste-stappen.adoc#_dictionaries zag je ze al even voorbij komen, in dit hoofdstuk leer je er uitgebreider mee werken.
Leerdoelen
Aan het einde van dit hoofdstuk:
-
Begrijp je wat een woordenboek is
-
Begrijp je in welke situatie je woordenboeken toe kunt passen
-
Begrijp je hoe je met elementen in een woordenboek kunt werken
Woordenboeken: een inleiding
In een (echt) woordenboek zoek je een bepaald woord op om daar de definitie of vertaling van te leren. In Python werken woordenboeken net zo. Een woordenboek, dictionary in het Engels en in Python afgekort tot dict
, is een type collectie waarbij je elementen niet opzoekt op basis van index (zoals bij lijsten), maar op basis van een sleutel. Bijvoorbeeld:
nederlands_engels = {
"programmeertaal": "programming language",
"opleiding": "course",
"leraar": "teacher",
}
In dit woordenboek zie je drie elementen, elk bestaande uit een sleutel (het Nederlandse woord) en de waarde (de Engelse vertaling). Dergelijke elementen worden vaak key-value pairs genoemd. De sleutels en waarden bestaan in dit voorbeeld uit tekst, maar een dict
is hier zeker niet toe beperkt.
In deze paragraaf leer je wat de kenmerken van woordenboeken zijn en in welke situaties je ze kunt gebruiken.
Kenmerken van woordenboeken
Een dict
kun je op verschillende manieren maken:
lege_dict_1 = {}
lege_dict_2 = dict()
dict_met_items = {
1: "a",
2: "b",
}
Een key-value pair bestaat altijd uit een sleutel en een waarde, gescheiden door een dubbele punt (:
). Meerdere key-value pairs in een dict
scheidt je met een komma. Net als bij een list
kun je achter het laatste element een komma plaatsen, maar dit is niet verplicht.
Je kunt ook een dict
maken van een list
(of tuple
) van key-value pairs. In onderstaand voorbeeld bevat mijn_lijst
drie tuples
, welke allemaal een key-value pair in de dict
zullen worden.
mijn_lijst = [
("a", 1),
("b", 2),
("c", 3),
]
mijn_dict = dict(mijn_lijst)
print(mijn_dict)
# {'a': 1, 'b': 2, 'c': 3}
De belangrijkste kenmerken van een dict
zijn:
-
Een
dict
is een type collectie. -
Je haalt waarden op basis van sleutels op uit een
dict
. -
Een
dict
is muteerbaar (aanpasbaar). Je kunt elementen toevoegen, aanpassen en verwijderen. -
De elementen hoeven niet van hetzelfde type te zijn. Dit geldt voor zowel de sleutels als de waarden.
Een aantal handelingen die je bij lijsten tegenkwam zijn ook bij een dict
mogelijk, maar niet alle. Je kunt:
-
Controleren of het element
i
in dedict
aanwezig is meti in mijn_dict
. -
Het aantal elementen ophalen met
len(mijn_dict)
. -
Het kleinste en grootste element ophalen met
min(mijn_dict)
enmax(mijn_dict)
.
Verder zijn er nog specifieke kenmerken voor de sleutels en de waarden.
Sleutels
De sleutels in een dict
moeten uniek te zijn. Het volgende heeft dust geen zin:
dubbel = {
"a": 1,
"a": 2,
}
Zoals je verderop zult zien, haal je waarden uit een dict
op basis van de sleutel op. Met dubbele sleutels weet Python niet welke waarde het terug moet geven. Je kunt de dict
wel op deze manier aanmaken, maar enkel de laatste a
zal opgeslagen worden.
Daarnaast moeten sleutels een onveranderlijk (immutable) type zijn. Vaak zul je tekst of integers als sleutel gebruiken, maar floats
en tuples
zijn ook toegestaan.
Voor nu is het voldoende om over sleutels te denken als uniek en onveranderlijk. Maar feitelijk ligt het genuanceerder, het gaat er namelijk om dat sleutels hashable moeten zijn. In de praktijk betekent dit dat een veranderlijke type wel als sleutel gebruikt kan worden, als het maar elke keer dezelfde hash oplevert. Een hash functie is een functie dat data van arbitraire grootte omzet naar data met een vaste grootte. De hash van het woord "Python" is: 18885f27b5af9012df19e496460f9294d5ab76128824c6f993787004f6d9a7db De hash van de zin "Python is super" is: 33b9132f634040992a01e4c77a462813cc624868c428c7cbfdb89c7a3d4ff397 |
Waarden
Waarden hoeven niet uniek te zijn binnen een dict
en mogen ook veranderlijk zijn. Het is dus mogelijk om bijvoorbeeld een list
of een andere dict
als waarde te hebben:
werknemers = {
"Ali": {
"leeftijd": 30,
"rol": "Manager",
"salaris": 5000
},
"Marie": {
"leeftijd": 25,
"rol": "Ontwikkelaar",
"salaris": 4000
},
"John": {
"leeftijd": 35,
"rol": "Analist",
"salaris": 4500
}
}
Hier zie je een dict
met als sleutels de naam van de werknemers, en als waarden een nieuwe dict
. Bijvoorbeeld: Ali
is een sleutel, met de dict
{"leeftijd: 30, …}
als waarde. Dit gegeven, dat de waardes van een dict
zelf ook weer bestaan uit een dict
, heet nesting. Dit is overigens niet beperkt tot één laag:
nested_dict = {
"fruit": {
"appel": {
"kleur": "rood",
"smaak": "zoet"
},
"banaan": {
"kleur": "geel",
"smaak": "zoet"
}
},
"groente": {
"wortel": {
"kleur": "oranje",
"smaak": "hartig"
},
"sla": {
"kleur": "groen",
"smaak": "knapperig"
}
}
}
Zolang je laptop of computer genoeg geheugen heeft, is er geen beperking aan het aantal lagen dat je kunt nesten.
De waarden van een dict
kunnen van elk type zijn.
Let op de leesbaarheid van dicts in het algemeen en bij geneste dicts in het bijzonder. Gebruik inspringingen om duidelijk te maken tot welk niveau elke laag hoort.
|
Wanneer woordenboeken te gebruiken
Een dict
is erg geschikt om te werken met data dat verschillende eigenschappen heeft. In werken-met-lijsten.adoc#_wanneer_gebruik_je_een_lijst zag je het voorbeeld van een list
voorbij komen met een aantal namen. Dit zou je nu kunnen uitbreiden naar een list
met dicts
. Bijvoorbeeld:
# Als lijst, alleen de naam
gebruikers = ["John", "Ali", "Marie", ]
# Als dict, met meer informatie
gebruikers = [
{"naam": "John", "leeftijd": 30},
{"naam": "Ali", "leeftijd": 30},
{"naam": "Marie", "leeftijd": 25},
]
Werken met elementen in een woordenboek
Zoals inmiddels duidelijk is, bestaat een dict
uit key-value pairs. Dit feit bepaalt de werking van hoe je met elementen in een dict
werkt. Je zult namelijk vaak de keuze moeten maken of je wilt werken met de sleutels, de waarden of beiden.
Een dict
heeft dan ook drie belangrijke methodes die je veel zult tegenkomen:
-
.keys()
-
.values()
-
.items()
Een voorbeeld maakt duidelijk wat elke methode doet:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
print(mijn_dict.keys())
# dict_keys(['naam', 'beroep', 'leeftijd'])
print(mijn_dict.values())
# dict_values(['Erwin', 'Auteur', 38])
print(mijn_dict.items())
# dict_items([('naam', 'Erwin'), ('beroep', 'Auteur'), ('leeftijd', 38)])
Elke methode levert een iterable op, je kunt het zien als een speciaal soort lijst. Je kunt er dus ook langs itereren:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
for key in mijn_dict.keys():
print(key)
# naam
# beroep
# leeftijd
De .items()
methode levert een lijst op waarbij elk element een tuple
is van de sleutel en bijbehorende waarde, zodat je met beiden kunt werken. Een voorbeeld hiervan zie je in Itereren langs een woordenboek als je leert een for-loop
te gebruiken met een dict
.
De .keys()
methode zul je in de praktijk zelden zien, omdat dit als de standaard wordt beschouwd. Laat je .keys()
weg, dan zul je de acties uitvoeren op de sleutels van de dict
. Bovenstaand voorbeeld kun je dus als volgt herschrijven:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
for key in mijn_dict: # Let op, geen .keys()!
print(key)
# naam
# beroep
# leeftijd
Kenmerken van een dict
ophalen
Met min()
, max()
en len()
haal je enkele kenmerken op van een dict
. Met len()
haal je het aantal elementen op. Voor len()
maakt het niet uit of je dit uitvoert op mijn_dict.keys()
, mijn_dict.values()
of mijn_dict.items()
, het resultaat is logischerwijs altijd hetzelfde.
Met min()
en max()
haal je de kleinste en grootste sleutel of waarde op:
mijn_dict = {
"a": 100,
"b": 10,
"c": 1,
}
print(len(mijn_dict)) # 3
print(min(mijn_dict)) # a
print(max(mijn_dict)) # c
print(min(mijn_dict.values())) # 1
print(max(mijn_dict.values())) # 100
Elementen uit een dict
ophalen
Je haalt de waarden uit een dict
op op basis van de sleutel. Dit kun je op twee manieren doen. De eerste lijkt op hoe je een element uit een list
ophaalt:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
naam = mijn_dict["naam"]
print(naam) # Erwin
Net als bij lijsten gebruik je haakjes ([]
), maar in plaats van een index gebruik je de sleutel, naam
in dit geval. Als de sleutel niet bestaat, krijg je een fout. Probeer maar eens om naam
te veranderen in Naam
, en kijk wat er gebeurt.
Om dit te voorkomen is er nog een andere manier om waarden op te halen, met de .get()
methode:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
naam = mijn_dict.get("naam")
print(naam) # Erwin
hobby = mijn_dict.get("hobby")
print(hobby) # None
default = mijn_dict.get("hobby", "Onbekend")
print(default) # Onbekend
In plaats van de haakjes te gebruiken, gebruik je de .get()
methode. Bestaat de sleutel niet, dan zal .get()
standaard None
teruggeven. Dit kun je echter aanpassen door een standaardwaarde op te geven, zoals op regel 9.
De .get()
methode is handig om in if
-statements te gebruiken:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
hobby = mijn_dict.get("hobby")
if not hobby:
print("Bezoek onze website voor inspiratie!")
Eerder zag je dat een dict
meerdere lagen diep kan zijn. Het ophalen van waarden uit de diepere lagen werkt hetzelfde als het ophalen van de eerste laag:
werknemers = {
"Ali": {
"leeftijd": 30,
"rol": "Manager",
"salaris": 5000
},
"Marie": {
"leeftijd": 25,
"rol": "Ontwikkelaar",
"salaris": 4000
},
"John": {
"leeftijd": 35,
"rol": "Analist",
"salaris": 4500
}
}
rol_ali = werknemers["Ali"]["rol"]
print(rol_ali) # Manager
Je verwacht misschien dat je dit ook kunt doen met meerdere aanroepen van .get()
. En dit werkt ook, maar levert alsnog fouten op als de eerste sleutel niet bestaat:
werknemers = {
"Ali": {
"leeftijd": 30,
"rol": "Manager",
"salaris": 5000
}
}
rol_erwin = werknemers.get("Erwin").get("rol")
# Sleutel 'Erwin' bestaat niet
# Fout: AttributeError
Omdat de sleutel Erwin
niet bestaat, wordt er None
teruggegeven. En None
heeft geen methode .get()
, waardoor een fout ontstaat. Er zijn manieren om dit op te lossen, één hiervan zul je leren in Werken met uitzonderingen, waar je leert hoe je fouten af kunt handelen.
Controleren of een element zich in een woordenboek bevindt
Net als bij een list
, kun je in
(en not in
) gebruiken om te controleren of een element zich in een dict
bevindt. Hierbij gaat het echter niet om de key-value pair, maar controleer je op de sleutel óf de waarde.
Gebruik je in
, dan controleer je standaard op de sleutels:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
print("naam" in mijn_dict) # True, "naam" is een sleutel
print("Erwin" in mijn_dict) # False, "Erwin" is géén sleutel
Om te controleren of een waarde zich in een dict
bevindt, voeg je .values()
toe aan de dict
:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
print("naam" in mijn_dict.values()) # False, "naam" is geen waarde
print("Erwin" in mijn_dict.values()) # True, "Erwin" is een waarde
Itereren langs een woordenboek
Omdat een dict
een collectie is, kun je for
gebruiken om langs de dict
te itereren. Bekijk wat er gebeurt als je dit doet:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
for element in mijn_dict:
print(element)
# naam
# beroep
# leeftijd
Je ziet dat elke sleutel wordt afgedrukt. Net als bij in
, kun je .values()
gebruiken om de waarden op te halen:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
for element in mijn_dict.values():
print(element)
# Erwin
# Auteur
# 38
Als je
Maar je mag |
In de meeste gevallen zul je echter willen itereren langs de sleutels én de waarden. Gebruik hiervoor .items()
:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
for key, value in mijn_dict.items():
print(f"{key}: {value}")
# naam: Erwin
# beroep: Auteur
# leeftijd: 38
Je ziet dat je ook twee variabelen in de for-loop
gebruikt. In het voorbeeld heten ze key
en value
, en dit zul je vaak zien. Maar je mag hier kiezen wat je wilt, bijvoorbeeld kenmerk
en waarde
.
Elementen wijzigen of toevoegen
Tot dusver heb je steeds een dict
gemaakt met een aantal key-value pairs. Een dict is echter aanpasbaar, en het is dus ook mogelijk om later elementen toe te voegen.
De meest eenvoudige manier is als volgt:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
mijn_dict["hobby"] = "Schrijven"
print(mijn_dict["hobby"]) # Schrijven
Je voegt tussen haakjes de sleutel toe en wijst vervolgens de waarde toe aan die sleutel.
Gebruik je een bestaande sleutel, dan zal de oude waarde overschreven worden:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
"hobby": "Schrijven",
}
mijn_dict["hobby"] = "Lezen"
print(mijn_dict["hobby"]) # Lezen
Een tweede manier om elementen aan een dict
toe te voegen is met de .update()
methode. Hiermee voeg je echter niet één key-value pair toe, maar voeg je twee dicts
samen, of voeg je een andere iterable met key-value pairs (zoals een list
) toe aan de dict
.
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
tweede_dict = {
"hobby": "Schrijven",
"taal": "Python",
}
mijn_dict.update(tweede_dict)
print(mijn_dict)
# {
# 'naam': 'Erwin',
# 'beroep': 'Auteur',
# 'leeftijd': 38,
# 'hobby': 'Schrijven',
# 'taal': 'Python'
# }
mijn_list = [("lengte", 1.78), ("favoriet_dier", "Cobra"), ]
mijn_dict.update(mijn_list)
print(mijn_dict)
# {
# 'beroep': 'Auteur',
# 'favoriet_dier': 'Cobra',
# 'hobby': 'Schrijven',
# 'leeftijd': 38,
# 'lengte': 1.78,
# 'naam': 'Erwin',
# 'taal': 'Python'
# }
Als je Je kunt hiervoor
Druk nu de In een later hoofdstuk leer je meer over |
Elementen verwijderen
Net als bij een list
, kun je bij een dict
ook del
gebruiken om elementen te verwijderen.
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
del mijn_dict["leeftijd"]
print(mijn_dict)
# {'naam': 'Erwin', 'beroep': 'Auteur'}
Ook .pop()
kun je bij een dict
gebruiken, en net als bij een list
verwijdert je hiermee het element én geef je het terug:
mijn_dict = {
"naam": "Erwin",
"beroep": "Auteur",
"leeftijd": 38,
}
naam = mijn_dict.pop("naam")
print(naam) # Erwin
print(mijn_dict)
# {'beroep': 'Auteur', 'leeftijd': 38}
In tegenstelling tot .pop()
bij een list
, geef je de sleutel op, niet een index. Gebruik je .pop()
zonder index bij een list
, dan zal het het laatste element teruggeven. Bij een dict
moet je .pop()
altijd een waarde meegeven.
Elementen sorteren en omkeren
Een dict
kun je sorteren en omkeren, net als je in het vorige hoofdstuk leerde bij lijsten. In tegenstelling tot bij een list
, heeft dict
geen eigen methodes .sort()
en .reverse()
. Je zult dus de ingebouwde functies sorted()
en reversed()
moeten gebruiken.
In Python hebben Dit had ook gevolgen voor het sorteren: je kon wel sorteren en het opslaan in een (nieuwe) Loop je tegen problemen met sorteren en omkeren aan, controleer dan of je Python versie 3.7 of hoger is. Typ |
Sorteren
Je kunt een dict
sorteren op basis van zowel de sleutels als de waarden. Sorteren op waarden is iets complexer en laten we hier buiten beschouwing. Om te sorteren op basis van de sleutel gebruik je de ingebouwde functie sorted()
. Echter, sorted()
geeft altijd een list
terug:
personen = {
"Marie": 36,
"Ali": 35,
"John": 38,
}
alfabetisch = sorted(personen)
# ["Ali", "John", "Marie"]
Dit kan nuttig zijn, maar hiermee is de dict
zelf niet gesorteerd. Om dit te bereiken gebruik je de .items()
methode, die je ook hebt gebruikt in de for-loop
. Met .items()
maak je een iterable van key-value pairs:
personen = {
"Marie": 36,
"Ali": 35,
"John": 38,
}
print(personen.items())
# dict_items([('Marie', 36), ('Ali', 35), ('John', 38)])
Omdat sorted()
met iterables werkt en .items()
een iterable oplevert, kun je beiden combineren om te sorteren:
personen = {
"Marie": 36,
"Ali": 35,
"John": 38,
}
alfabetisch = sorted(personen.items())
print(alfabetisch)
# [('Ali', 35), ('John', 38), ('Marie', 36)]
alfabetisch = dict(alfabetisch)
print(alfabetisch)
# {'Ali': 35, 'John': 38, 'Marie': 36}
Omdat sorted()
een list
oplevert, maak je er met dict()
weer een dict
van. Dit kan overigens ook in één regel:
alfabetisch = dict(sorted(personen.items()))