Dictionaries and default values
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When accessing a dictionary key that might not exist, Python raises KeyError by default. To avoid this, you can use dict.get() for a fallback value, collections.defaultdict for automatic defaults, dict.setdefault() to set-and-return, or the | merge operator to overlay defaults onto user input. Each method serves a different use case — get() for read-only access, defaultdict for building up values, and setdefault() for one-time initialization.
The Problem: KeyError
Accessing a missing key crashes the program. Default values prevent this.
Method 1: dict.get() (Most Common)
get() never modifies the dictionary. It is a read-only operation.
Method 2: collections.defaultdict
defaultdict calls the factory function whenever a missing key is accessed, and stores the result in the dictionary.
Method 3: dict.setdefault()
setdefault() modifies the dictionary (unlike get()). Use it when you want to initialize a key only on first access.
Method 4: Merge Operator for Defaults (Python 3.9+)
The right-hand dictionary wins on duplicate keys, so put defaults on the left and overrides on the right.
Method 5: try/except
This follows the EAFP (Easier to Ask Forgiveness than Permission) pattern. Use it when you need to handle missing keys differently from providing a default.
Method 6: The in Operator
This LBYL (Look Before You Leap) approach is explicit but verbose. get() is preferred for simple default values.
Nested Dictionary Defaults
Pattern: Configuration with Defaults
Common Pitfalls
get()with mutable default:d.get("key", [])returns a new empty list each time. If you want to build up a list, usesetdefault()ordefaultdict(list)instead, which stores the default in the dict.defaultdictcreates keys on read: Accessingd["missing"]on adefaultdictinserts the key with the default value. If you only want to check without creating, usekey in dord.get(key).setdefault()evaluates the default eagerly:d.setdefault("key", expensive_function())calls the function even if the key exists. For expensive defaults, useif key not in d: d[key] = expensive_function().Nonevs missing:d.get("key")returnsNonefor both{"key": None}and{}. IfNoneis a valid value, usekey in dto distinguish.dict.fromkeys()shares mutable defaults:dict.fromkeys(["a", "b"], [])makes both keys point to the same list. Use{k: [] for k in keys}instead.
Summary
- Use
dict.get(key, default)for read-only access with a fallback value - Use
defaultdict(factory)when building up collections (counting, grouping) - Use
dict.setdefault(key, default)for one-time initialization of a key - Use
{**defaults, **overrides}ordefaults | overridesto merge configuration dicts get()does not modify the dict;setdefault()anddefaultdictdo- Check
key in dwhenNoneis a valid value and you need to distinguish it from a missing key

