Dictionary — Paare aus Key und Wert
Werte nach Namen speichern und holen, KeyError mit .get() vermeiden, Keys hinzufügen und löschen, mit .items() durchlaufen und warum eine Liste kein Key sein kann.
Wie möchtest du lernen?
Das Problem, das wir lösen
Die Noten von drei Leuten müssen gespeichert werden — mit der Angabe, wem welche Note gehört.
Listen bieten nur einen Weg: zwei Listen nebeneinander.
names = ["rafi", "ahmed", "bilal"]
marks = [72, 45, 90]
print(names[1], marks[1])ahmed 45Es funktioniert. Und das ganze Gebilde hängt an deiner Disziplin, ganz ohne Hilfe von Python.
Du fügst jemanden zu names hinzu und vergisst marks? Die beiden Listen haben jetzt unterschiedliche Längen, und von da an beschreiben names[2] und marks[2] zwei verschiedene Personen. Python sagt kein Wort. names sortieren? Die Beziehung bricht vollständig — und zwar still.
Hier sitzt der Ursprung: die Beziehung zwischen den beiden Dingen steht nirgends im Code. Die Beziehung ist nur „derselbe Index“ — ein Zufall, der jederzeit brechen kann.
Ein Dictionary schreibt die Beziehung mit in den Code. Namen statt Indizes, und das Paar wird an einem Ort zusammengehalten.
Am Ende dieses Kapitels kannst du
- Ein Dictionary bauen und einen Wert über seinen Key holen
- Einen
KeyErrormit.get()vermeiden und wissen, wann was richtig ist - Keys hinzufügen, ändern und löschen
- Ein Dictionary mit
.keys(),.values()und.items()durchlaufen - Erklären, warum eine Liste kein Key sein kann, ein Tupel aber schon
Voraussetzungen: Tupel und Entpacken.
Ein Dictionary — Paare aus Key und Wert
Geschweifte Klammern, mit key: value-Paaren darin:
marks = {"rafi": 72, "ahmed": 45, "bilal": 90}
print(marks)
print(marks["ahmed"])
print(len(marks)){'rafi': 72, 'ahmed': 45, 'bilal': 90}
45
3marks["ahmed"] — ein Name, kein Index. Und der Name steht direkt im Code, also sagt er auch sechs Monate später noch, wonach gefragt wird.
len() zählt die Paare: drei.
Ein Wort zur Reihenfolge. Seit Python 3.7 merkt sich ein Dictionary, in welcher Reihenfolge die Dinge hineingekommen sind, und gibt sie auch so aus. Aber ein Dictionary ist zum Nachschlagen nach Namen da, nicht nach Position — schreibmarks[0], und Python sucht einen Key, der die Zahl null ist, findet keinen und stoppt mitKeyError: 0.
Ein Key, den es nicht gibt — KeyError und .get()
marks = {"rafi": 72}
print(marks["dia"])KeyError: 'dia'Ein KeyError bedeutet „es gibt keinen Key mit diesem Namen“. Derselbe Fehler bei einer Liste gab einen IndexError — ein anderer Name für dieselbe Art von Fehler.
Für eine sichere Antwort statt eines Abbruchs nimm .get():
marks = {"rafi": 72}
print(marks.get("dia"))
print(marks.get("dia", 0))
print(marks.get("rafi", 0))None
0
72Das zweite Argument bedeutet „gib mir das, wenn es fehlt“. Ohne ein solches bekommst du None.
Was wann? Wenn der Key da sein sollte, schreib marks["rafi"] — sein Fehlen ist ein Bug, und der KeyError reicht ihn dir sofort. Wenn es normal ist, dass der Key fehlt, nimm .get(). Überall .get() zu benutzen lässt schlechte Daten still durchrutschen — und schlechte Daten waren es doch, die du finden wolltest.
Hinzufügen, Ändern, Löschen
marks = {"rafi": 72}
marks["dia"] = 88
marks["rafi"] = 75
print(marks)
del marks["rafi"]
print(marks){'rafi': 75, 'dia': 88}
{'dia': 88}Dieselbe Zeile erledigt zwei Aufgaben: Fehlt der Key, wird er hinzugefügt; existiert er, wird er ersetzt. Es gibt keine eigene „Hinzufügen“-Methode.
Und daraus folgt eine wichtige Regel — ein Key kann nur einmal vorkommen:
marks = {"rafi": 72, "rafi": 90}
print(marks){'rafi': 90}Kein Fehler. Der zweite hat den ersten stillschweigend überschrieben. Das passiert regelmäßig beim Laden von Daten aus einer Datei und ist eine häufige Ursache dafür, dass Datensätze fehlen.
in sucht in den Keys, nicht in den Werten
marks = {"rafi": 72, "ahmed": 45}
print("rafi" in marks)
print(72 in marks)True
False72 ist sicher als Wert dabei, aber in schaut nur unter den Keys. Um die Werte zu durchsuchen, musst du das ausdrücklich sagen: 72 in marks.values().
Durchlaufen, auf drei Arten
marks = {"rafi": 72, "ahmed": 45}
for name in marks:
print(name)
print("---")
for name, mark in marks.items():
print(name, mark)
print("---")
print(list(marks.keys()))
print(list(marks.values()))rafi
ahmed
---
rafi 72
ahmed 45
---
['rafi', 'ahmed']
[72, 45]Die erste Art ist bemerkenswert: for name in marks liefert dir die Keys, nicht die Werte. Das überrascht beim ersten Mal jeden.
Wenn du beide willst, gibt .items() in jeder Runde ein Tupel zurück — und name, mark entpackt es. Hier zahlt sich das Entpacken aus dem letzten Kapitel aus.
Um mit den Werten zu rechnen, .values():
marks = {"rafi": 72, "ahmed": 45, "bilal": 90}
print(sum(marks.values()))
print(max(marks.values()))
print(round(sum(marks.values()) / len(marks), 2))207
90
69.0Was ein Key sein kann
Damit etwas ein Key ist, muss es unveränderlich sein. Text, Zahlen und Tupel funktionieren alle. Eine Liste nicht:
d = {}
d[["a", "b"]] = 1TypeError: unhashable type: 'list'Das Wort „unhashable“ lohnt sich, es einmal auseinanderzunehmen. Ein Dictionary findet Dinge so schnell, weil es aus jedem Key eine Zahl berechnet und mit dieser Zahl direkt an die richtige Stelle springt. Wenn sich der Key danach ändern könnte, wäre diese Zahl falsch und der Eintrag verloren. Also weigert sich Python, irgendetwas Veränderliches überhaupt als Key zuzulassen.
Ein Tupel kann nicht verändert werden, was es zu einem exzellenten Key macht:
grid = {}
grid[(0, 0)] = "start"
grid[(1, 2)] = "tree"
print(grid)
print(grid[(1, 2)]){(0, 0): 'start', (1, 2): 'tree'}
treeDas letzte Kapitel nannte die Unveränderlichkeit eines Tupels einen Vorteil. Das ist der erste praktische Beweis dafür.
Das nützlichste Muster überhaupt — Zählen
words = ["pen", "bag", "pen", "ink", "pen"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts){'pen': 3, 'bag': 1, 'ink': 1}Lies die Zeile von innen: counts.get(word, 0) sagt „gib mir den bisherigen Zählerstand dieses Wortes, und null, wenn es noch keinen hat“, dann wird eins addiert und das Ergebnis zurückgeschrieben.
Der Standardwert von .get() erledigt hier die ganze Arbeit — ohne es würde jedes neue Wort einen KeyError werfen, und du bräuchtest if word in counts: und zwei Zweige. Dieses Einzeiler-Muster wirst du viele Male schreiben.
Ein vollständiges Beispiel
marks.py:
# A dictionary keeps a name attached to its value
marks = {"rafi": 72, "ahmed": 45, "bilal": 90, "dia": 88}
print("Everyone:")
for name, mark in marks.items():
status = "pass" if mark >= 40 else "fail"
print(f" {name:<8} {mark:>3} {status}")
print()
print("Count :", len(marks))
print("Total :", sum(marks.values()))
print("Average :", round(sum(marks.values()) / len(marks), 2))
print("Highest :", max(marks.values()))
best = max(marks, key=marks.get)
print("Best :", best, marks[best])
print("Has dia :", "dia" in marks)
print("Missing :", marks.get("nadia", "not recorded"))
marks["dia"] = 91
marks["nadia"] = 60
del marks["ahmed"]
print()
print("After edits:", marks)Everyone:
rafi 72 pass
ahmed 45 pass
bilal 90 pass
dia 88 pass
Count : 4
Total : 295
Average : 73.75
Highest : 90
Best : bilal 90
Has dia : True
Missing : not recorded
After edits: {'rafi': 72, 'bilal': 90, 'dia': 91, 'nadia': 60}Drei Dinge, die dir auffallen sollten.
status = "pass" if mark >= 40 else "fail" ist eine Möglichkeit, eine Bedingung in einer Zeile zu schreiben — von der Mitte nach außen gelesen: „"pass" wenn mark >= 40, sonst "fail"“. Das vierzeilige if/else aus Kapitel neun wählt hier nur einen einzelnen Wert, also reicht eine Zeile. Für eine echte Entscheidung schreib ein vollständiges if — diese Form dient nur dazu, einen von zwei Werten auszuwählen.
max(marks, key=marks.get) ist das key= aus Kapitel dreizehn in neuer Rolle. (Hier ist key= der Name eines Arguments von max, kein Dictionary-Key.) max(marks) liefert den größten Key, also den letzten Namen alphabetisch. key=marks.get sagt, jeden Key stattdessen anhand seines Werts zu vergleichen — und das ergibt den Namen mit der höchsten Note. Beachte: Die höchste Note zu bekommen ist einfach (max(marks.values())); herauszufinden, wem sie gehört, braucht diesen Trick.
Die Reihenfolge in der letzten Zeile. dia hat es schon gegeben, also änderte sich nur der Wert, nicht die Position. nadia ist neu, also kam es am Ende hinzu. Und ahmed ist weg. Ein Dictionary merkt sich die Einfügereihenfolge, und einen Wert zu ersetzen stört sie nicht.
Wenn etwas schiefgeht
KeyError: 'dia' Es gibt keinen Key mit diesem Namen. Prüfe Schreibweise und Groß-/Kleinschreibung — "Rafi" und "rafi" sind zwei verschiedene Keys. Keys, die aus einer Datei gelesen wurden, haben oft ein nachgestelltes Leerzeichen; print(list(d.keys())) setzt um jeden herum Anführungszeichen, damit man es sieht. Wenn es normal ist, dass der Key fehlt, nimm .get().
TypeError: unhashable type: 'list' Ein Versuch, eine Liste als Key zu verwenden. Nimm ein Tupel — tuple(my_list) baut eines.
for x in my_dict liefert mir nicht die Werte Und das soll es auch nicht — es liefert die Keys. Für Werte .values(), und für beides .items().
Zwei Keys waren gleich, und ein Datensatz ist verschwunden Ein Key existiert nur einmal, und der spätere hat den früheren stillschweigend ersetzt. Um mehrere Datensätze unter einem Namen zu speichern, mache den Wert zu einer Liste — das Thema von Kapitel siebzehn.
KeyError: 0 Der Code hat my_dict[0] geschrieben und nach dem ersten Element gefragt, als wäre es eine Liste. Ein Dictionary hat keine Positionen; 0 wird als Key nachgeschlagen, und wenn es diesen Key nicht gibt, kommt KeyError: 0. Wenn du wirklich das erste Paar brauchst, schreib list(my_dict.items())[0].
.sort() funktioniert an einem Dictionary nicht Richtig — Dictionaries haben keine .sort(). sorted(d.items()) liefert eine sortierte Liste, und meistens ist das das, was du wolltest.
Schritt 4 von 6 — Vorhersagen
Prüfe dein Verständnis
Eine Schleife läuft direkt über ein Dictionary. Was wird ausgegeben?
marks = {"rafi": 72, "ahmed": 45}
for name in marks:
print(name)- Arafi 72 ahmed 45
- Brafi ahmed
- C72 45
- D('rafi', 72) ('ahmed', 45)
Es wird nach einem Key gefragt, den es nicht gibt. Was passiert, und was ist die sichere Alternative?
marks = {"rafi": 72}
print(marks["dia"])- AEs gibt `None` aus
- BEs gibt eine Leerzeile aus
- CEin `KeyError` — die sichere Alternative ist `marks.get("dia")`, das `None` liefert
- DEin `IndexError`
Das Zählmuster. Was wird ausgegeben?
words = ["pen", "bag", "pen"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts)- AEin `KeyError`
- B{'pen': 2, 'bag': 1}
- C{'pen': 1, 'bag': 1}
- D{'pen': 3, 'bag': 1}
Zum Antworten brauchst du ein Konto
Melde dich an, um deine Antworten zu prüfen
Die Fragen stehen oben, und sie im Kopf durchzuarbeiten ist der wichtige Teil. Melde dich an, um die Antworten, die Erklärungen und die dreistufigen Hinweise zu sehen.
Jetzt bist du dran
Schreib eine Datei namens stock.py mit einem Dictionary von mindestens sechs Produkten — der Produktname als Key, der Preis als Wert.
Dann:
- Gib jedes Produkt und seinen Preis in ausgerichteten Spalten aus
- Gib die Summe, den Durchschnitt, den höchsten und den niedrigsten Preis aus
- Finde den Namen des teuersten Produkts, nicht nur den Preis
- Füge ein Produkt hinzu, ändere einen Preis, lösche ein Produkt und gib dann alles noch einmal aus
- Benutze
.get(), um nach einem Produkt zu fragen, das es nicht gibt, mit einer Meldung als Standardwert
Dann schreib ein Zählprogramm: Leg mehrere Wörter in eine Liste, manche mehrfach, und zähle mit dem Muster counts.get(word, 0) + 1, wie oft jedes vorkommt.
Zum Schluss brich es absichtlich: Frag nach einem fehlenden Key mit eckigen Klammern und versuch, eine Liste als Key zu verwenden. Zwei verschiedene Fehler kommen zurück — erkläre dir selbst, welcher welcher ist und warum.
Schritt 6 von 6
Herausforderung — das Kapitel-Quiz
Zehn Fragen von leicht bis schwer. Die letzten sind absichtlich knifflig.
Melde dich an, um das Quiz zu machen