Dictionary .get() -- leeres Dictionary als Default

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
PyTimmi

Hallo zusammen,

ich möchte gerne etwas zählen und die Ergebnisse in einem verschachtelten Dictionary speichern. Und zwar pro Name und Wochentag.
Mein Dictionary soll so aussehen:

Code: Alles auswählen

anzahl = {"Jupp": {"Montag": 1, "Dienstag": 0, "Mittwoch": 0, "Donnerstag": 0, "Freitag": 0, "Samstag": 0, "Freitag": 0}, "Maximilian": {"Montag": 0, "Dienstag": 0, "Mittwoch": 0, "Donnerstag": 0, "Freitag": 0, "Samstag": 0, "Freitag": 0}}
Im Programm soll geprüft werden, ob der Name schon im Dictionary enthalten ist. Falls ja, soll der Zähler bei dem Namen und bei dem Wochentag um 1 hochgezählt werden. Falls nein, soll als Default-Wert eine 0 eingetragen und um 1 hochgezählt werden.

Code: Alles auswählen

anzahl["Julia"]["Montag"] = anzahl.get("Julia", {}).get("Montag", 0) + 1
Allerdings kommt es hierbei immer zu einem Key-Error 'Julia'.
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

Natürlich kommt ein KeyError, wenn Julia nicht existiert, denn darauf greifst Du ja über `anzahl["Julia"]` zu.
Für Deinen Zweck benutzt man defaultdict und Counter:

Code: Alles auswählen

from collections import defaultdict, Counter
anzahl = defaultdict(Counter)                                                                                                                                                                                  
anzahl["Julia"]["Montag"] += 1
PyTimmi

Aber dafür gibt es doch die get()-Funktion?
Wenn der Schlüssel nicht existiert, wird ein Default-Wert zurückgegeben.

Ich verstehe grade nicht, warum es da nicht geht.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Das Problem ist nicht das get. Das Problem befindet sich auf der _linken_ Seite des =.
Es befindet sich kein Schlüssel "Julia" in dem dict "anzahl".
PyTimmi

Ja, aber das funktioniert so mit get(). Zumindest dann, wenn es kein verschachteltes Dictionary ist. Dann legt Python eben den fehlenden Key an.

Code: Alles auswählen

anzahl = dict()
anzahl["Gustav"] = anzahl.get("Gustav", 0)
print(anzahl)
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

.get ist dazu da bei der Auswertung einen default-Wert zurück zu geben.
Das Verhalten in deinem letzten Post hat nichts mit .get zu tun.

Du weißt dem Schlüssel "Gustav" des dicts "anzahl" einen Wert zu. Nämlich das was auf der rechten Seite des = ausgewertet wird. Da könnte auch "Hamptitampti" stehen.

Und jetzt schau dir mal an, was das macht:

Code: Alles auswählen

anzahl["Julia"]["Montag"] = anzahl.get("Julia", {}).get("Montag", 0) + 1
Auf der rechten Seite:
Der Wert mit dem Schlüssel "Julia" oder ein leeres dict. (in diesem Fall ein leeres dict)
Aus dem vorherigen dict den Schlüssel "Montag" oder 0. (in diesem Fall 0)
Der Wert + 1
Das Ergebnis ist also 1. Das ist was auf der rechten Seite evaluiert wird.

Und wo genau wird jetzt deiner Meinung nach dem Schlüssel "Julia" in dem dict "anzahl" in irgend einer Weise etwas zugewiesen?
PyTimmi

Ok, ich will es mal anders formulieren.

Warum funktioniert das hier:

Code: Alles auswählen

tab = dict()
tab["Julia"] = 0
Aber das hier nicht (wenn das Dict verschachtelt sein soll):

Code: Alles auswählen

tab = dict()
tab["Julia"]["Montag"] = 0
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Warum funkioniert das:

Code: Alles auswählen

i = 1
print(i)
und das hier nicht?

Code: Alles auswählen

print(xy)
Du hast doch dem Schlüssel "Julia" gar nichts zugewiesen? Woher soll das denn ein Objekt werden, das Index-Zugriffe erlaubt? Denn du willst ja einen Index-Zugriff auf den Wert oder das Objekt machen, der sich hinter dem Schlüssel "Julia" verbirgt. Aber dafür muss sich ja erst einmal etwas hinter dem Schlüssel verbergen.
Wenn du so ein Verhalten möchtest, brauchst du ein "Defaultdict". Das hat dir Sirius3 ja schon gezeigt.
PyTimmi

Jetzt weiß ich, was du meinst. Vielen Dank :)
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Nur mal so am Rande was man da eventuell vor `collections.defaultdict` gemacht hat:

Code: Alles auswählen

In [162]: anzahl = {}

In [163]: anzahl["Julia"]["Montag"] = anzahl.setdefault("Julia", {}).get("Montag", 0) + 1

In [164]: anzahl
Out[164]: {'Julia': {'Montag': 1}}
`dict.setdefault()` war aber schon ein bisschen speziell und heute geradezu obskur, dass es die Methode immer noch gibt. IMHO. 😎
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
DeaD_EyE
User
Beiträge: 1244
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__blackjack__ hat geschrieben: Samstag 22. Oktober 2022, 22:31 `dict.setdefault()` war aber schon ein bisschen speziell und heute geradezu obskur, dass es die Methode immer noch gibt. IMHO. 😎
Damals hatten wir nichts Besseres, bis dann defaultdict kam.


Wenn das unbedingt dicts in dicts sein soll und nur die 2 Ebenen sind, kann man auch ein defaultdict verwenden:

Code: Alles auswählen

from collections import defaultdict


dd = defaultdict(dict)

# geht noch
dd["a"]["b"] = 3

# geht nicht
dd["x"]["y"]["z"] = 3
Ob das sinnvoll ist oder nicht, kann man sich darüber streiten.

Und das geht nicht:

Code: Alles auswählen

dd["a"] = 3
dd["a"]["b"] = 3
Da hat man dann dem Key "a" ein Integer zugewiesen und wenn man auf "a" zugreift, bekommt man den Integer zurück und kein leeres dict.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten