Dict Default Patterns

Deep dive · part of Python Dictionaries

Three idioms remove most if key in d checks: dict.get(k, default) for reads, dict.setdefault(k, default) for read-or-init, and collections.defaultdict for factories.

dict.get(key, default) reads without KeyError; setdefault initializes missing keys once; defaultdict(factory) automates factory on access. Picking the right idiom removes cluttered if key in d branches in aggregation and config parsing code.

setdefault is not atomic across threads—use locks or defaultdict in concurrent code. get is best for read-mostly paths with sentinel defaults.

Production code combines this topic with logging, tests, and clear module boundaries so refactors stay safe when requirements grow.

get never inserts; setdefault inserts default if missing then returns value.

defaultdict(list) appends with d[key].append without existence checks.

defaultdict(int) counts frequencies with d[token] += 1.

merge (|) and update (|=) combine mappings (3.9+ / 3.9+).

dict comprehension builds inverted indexes in one pass.

Missing keys in nested dicts still need setdefault per level or defaultdict of defaultdict.

For JSON parsing with optional fields, dataclasses with defaults often beat manual dict.get chains. When keys are expensive to compute, cache them outside loops instead of repeated setdefault.

ChainMap layers defaults for configuration without copying entire dicts.

TypedDict and dataclasses replace many dict.get chains in APIs; defaultdict remains ideal when keys are dynamic runtime identifiers.

TypedDict fits fixed schemas; defaultdict fits dynamic keys like file stems discovered at runtime.

Read the parent tutorial on pythondeck.com for runnable snippets, then reproduce them locally in a virtual environment with pinned dependency versions matching your deployment target.

When pairing with teammates, agree on one idiomatic pattern per concern—mixed styles in one repo slow reviews and invite subtle integration bugs during merges.

Using setdefault when get suffices, accidentally inserting keys on probe.

Mutable default arguments def f(d={}) instead of fresh dict per call.

defaultdict(lambda: [])—use list factory without lambda (use list).

Assuming setdefault is thread-safe for lazy initialization.

Prefer get for read-only defaults; setdefault for build-on-first-access.

Use defaultdict in grouping and counting loops.

Type hint dict[str, list[str]] for grouped structures.

Snapshot dict with copy() before iterating if mutating during loop.

Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.

The program below demonstrates get vs setdefault. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# Example: get vs setdefault
# Run in the REPL or save as a .py file and execute with python.
scores = {"math": 90}
print(scores.get("phys", 0))   # safe read
scores.setdefault("phys", []).append(70)   # init list once
scores.setdefault("phys", []).append(80)
print(scores)

This sample walks through defaultdict in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# Example: defaultdict
# Run in the REPL or save as a .py file and execute with python.
from collections import defaultdict
groups = defaultdict(list)
for word in "apple ant bee bear cat cow".split():
    groups[word[0]].append(word)
print(dict(groups))

Here is a hands-on illustration of dict comprehension w/ default. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.

# Example: dict comprehension w/ default
# Run in the REPL or save as a .py file and execute with python.
rows = [("a", 1), ("b", 2), ("a", 3)]
from collections import defaultdict
agg = defaultdict(int)
for k, v in rows: agg[k] += v
print(dict(agg))

The program below demonstrates setdefault list. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# setdefault inserts default once — great for grouping
scores = {"math": 90}  # existing
scores.setdefault("phys", []).append(70)  # create list then append
scores.setdefault("phys", []).append(80)  # same list mutated
print(scores)  # phys has two grades
print(scores.get("chem", 0))  # safe read with default
print("math" in scores)  # membership on keys
scores.setdefault("chem", 0)  # insert default for missing key
print(scores["chem"])  # 0

This sample walks through defaultdict groups in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# defaultdict factory avoids KeyError on first access
from collections import defaultdict  # factory dict
groups = defaultdict(list)  # key -> list
for word in "apple ant bee".split():  # words
    groups[word[0]].append(word)  # group by first letter
print(dict(groups))  # plain dict view
print(len(groups))  # number of first-letter buckets
print(groups["a"])  # words starting with a

« back to Python Dictionaries All tutorials