Klasický pythoní slovník můžete v principu vyrobit především následujícími dvěma metodami:
Type collections.defaultdict
řeší právě tento druhý problém – jakou výchozí hodnotu přiřadit dosud neexistujícímu klíči.
Spočítejme výskyt jednotlivých písmen v textu:
Zde není co řešit – existuje-li již příslušný klíč ve slovníku, zvýšíme příslušný počet o jedničku, neexistuje-li, znamená to, že jsme na něj natrefili poprvé, a tak ho zavedeme s výchozí hodnotou 1. Průhledné a zdánlivě to už snáz nejde.
Místo dotazování na existenci klíče můžeme také použít metodu „prostě to zkus a uvidíš“:
Výsledek je pochopitelně stejný.
Nyní vyřešme předchozí úlohu pomocí defaultdict:
Zde je chování mnohem zajímavější – přidávací smyčka jakoby interně předpokládala, že příslušný klíč v poli už vždy existovat bude! A přesně to se také oklikou děje – pokud totiž pokus o přečtení hodnoty xd[x]
(tedy vyhledání klíče x
) selže, je automaticky vytvořen s hodnotou získanou zavoláním funkce předané jako vstupní parametr konstruktoru slovníku s výchozími hodnotami (zde int(), která vrací 0).
defaultdict je prakticky ve všem úplně stejný jako klasický slovník. Jedinou výjimkou je právě první parametr konstruktoru, kterým je odkaz na vytvořující funkci (a pak už může následovat klasický iterovatelný objekt jako u xd = dict(ITERABLE)):
xd = collections.defaultdict([default_factory[, ITERABLE]])
Neuvedení prvního parametru nastaví vlastnost xd.default_factory na None
a jakýkoliv neexistující klíč pak vyhodí výjimku KeyError. Takže ve většině případů má větší smysl tam skutečně referenci na nějakou funkci uvést ^_^ Přitom tou funkcí může s výhodou být třebas i lambda-funkce, jak ukazuje přepis předchozího příkladu:
Poněkud staršího data je metoda slovníku setdefault(), která také umožňuje nastavit hodnotu pro neexistující klíč, ale dle mého názoru velmi kriptickým způsobem a navíc je zrovna tímto způsobem použitelná pouze pro typy s metodami:
Na druhou stranu se narozdíl od defaultdict() konstruktor výchozí hodnoty u setdefault() volá pro každý dosud neexistující klíč znovu během vykonávání smyčky for-in, takže ho třeba můžete průhledně učinit závislým na klíči a podobně.
PS: Je tu ještě jeden drobný rozdíl – zatímco u defaultdict() je vytvořující funkce pro všechny neznámé klíče stejná, u setdefault() ji můžete zvolit nezávisle pro každý klíč jinak v okamžiku použití (ne tedy zrovna takhle jednoduše uvnitř smyčky).
Jako vytvořující funkce se často používají vestavěné konstruktory jako list, set, dict nebo int. Výhodou defaultdictu však je, že v použité funkci se můžete docela vyřádit:
Všimněte si ale, že vytvořující funkce obdržela proměnnou klíče x
automaticky z okolního kontextu!
x
ve for-in a if-in bohužel není jen pouhá shoda jmen proměnných – lambda-funkce musí opravdu odkazovat na již existující příslušnou proměnnou cyklu :-(
setdefault() se v tomto případě chová výrazně rozumnějí, protože klíč získává hodnotu předáním jako argument funkce:
Chcete-li se tudíž ve vytvořující funkci jaksepatří „vyřádit“, je setdefault() lepší volba.