Mind a két nyelvi eszköz arra való, hogy ha egy szótárban nincs egy megadott kulcs, akkor ezt a kulcsot automatikusan felveszi a szótárba egy meghatározható alapértelmezett értékkel.
Ha d egy dict típusú szótár, akkor a d.setdefault(k, default) híváskor a default argumentum kiértékelődik és, amennyiben nincs a k kulcs a szótárban, az így létrejövő objektum lesz a k-hoz rendelt érték, majd e kulcs-érték pár bekerül a d szótárba. A setdefault visszatérési értéke mindig az aktuális kulcshoz tartozó érték.
A defaultdict egy olyan speciális szótár, amely példányosításakor első argumentumként egy paraméter nélküli hívható objektumot kell megadni. Ha e szótárban nincs egy megadott kulcs, akkor ez a hívható objektum lefut és visszatérési értéke lesz a kulcshoz tartozó érték. Ez a kulcs-érték pár bekerül a defaultdict szótárba.
A fő eltérés a kettő között, hogy míg a d.setdefault(k, default) minden hívásnál előállítja a default paraméternek átadott objektumot, addig a defaultdict szótárhoz megadott hívható objektum csak akkor fut le, ha a kulcs nincs a szótárban.
Ez az eltérés sok kulcs esetén jelentős futási időbeli különbséget hozhat.
Ennek szemléltetésére vegyünk egy egyszerű példát. Tegyük fel, hogy rendelkezésre áll egy adatbázis, amelyben a könnyű átláthatóság kedvéért csupán személyneveket és hozzájuk tartozó életkort tárolunk. A feladat az, hogy adott név alapján állítsuk elő a Személy osztály egy példányát, és a név-példány párt egy szótárba gyűjtsük. Kiegészítő követelmény, hogy az egyes Személy példányokban a neveket nagybetűvel tároljuk el. A neveket mint bemeneti adatokat egy sorozatban kapjuk. A sorozatban ugyanaz a név többször is előfordulhat.
Az alábbi programsorokban a feladatot mind setdefault, mind defaultdict alkalmazásával megoldottuk. A Személy osztályban az inicializáláskor a kor értéke vagy a konstruktorból jön, vagy ha itt nem adtuk meg, akkor a név-kor adatokat tároló adatbázisból, amit most egy szótárral modelleztünk. Minden egyes Személy példány létrehozásakor egy tájékoztató üzenetet írunk ki. A bejövő névadatok egy listában állnak rendelkezésre, amelyben a neveket kétszer ismételtük, hogy érzékelhető legyen, hogy mikor kell alapértelmezett értéket a szótáraknak előállítani és mikor nem.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
from collections import defaultdict # Adatbázist modellező szótár. adatbázis = {'Áron': 45, 'Mátyás': 68, 'Kati': 18} class Személy: def __init__(self, név: str, kor=None): self.név = név print('Példányosítás...') self.kor = kor if kor is not None else adatbázis.get(név) def __repr__(self): return f'{type(self).__name__}({self.név},{self.kor})' # A feldolgozandó személynevek sorozata. nevek = ['Áron', 'Mátyás', 'Kati'] * 2 # dict.setdefault() alkalmazása. d = {} for név in nevek: d[név].név = d.setdefault(név, Személy(név)).név.upper() print(dict(d)) # Eredmény: # Példányosítás... # Példányosítás... # Példányosítás... # Példányosítás... # Példányosítás... # Példányosítás... # {'Áron': Személy(ÁRON,45), 'Mátyás': Személy(MÁTYÁS,68), 'Kati': Személy(KATI,18)} # defaultdict() alkalmazása. dd = defaultdict(lambda: Személy(név)) for név in nevek: dd[név].név = dd[név].név.upper() print(dict(dd)) # Eredmény: # Példányosítás... # Példányosítás... # Példányosítás... # {'Áron': Személy(ÁRON,45), 'Mátyás': Személy(MÁTYÁS,68), 'Kati': Személy(KATI,18)} |
A két megoldás végeredményében ugyanazt adja, de látható, hogy setdefault esetén kétszer annyi Személy példány előállítása történt, mint defaultdict alkalmazása esetében. Mivel példányosításkor a valóságban adatbázis lekérdezés történik, így annak ideje sok példány előállításakor már nem biztos, hogy elhanyagolható.