Seite 1 von 1

Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 16:27
von 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'.

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 16:47
von Sirius3
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

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:12
von 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.

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:15
von sparrow
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".

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:20
von 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)

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:29
von sparrow
.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?

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:36
von 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

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:40
von sparrow
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.

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 17:44
von PyTimmi
Jetzt weiß ich, was du meinst. Vielen Dank :)

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Samstag 22. Oktober 2022, 22:31
von __blackjack__
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. 😎

Re: Dictionary .get() -- leeres Dictionary als Default

Verfasst: Montag 24. Oktober 2022, 19:50
von DeaD_EyE
__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.