Grouping Data with collections.defaultdict
Use defaultdict factories to group values and initialize missing keys while understanding when lookups do and do not create entries.
Intermediate
A normal dictionary waits for you to decide what should happen when a key is missing. Sometimes a missing key has a predictable starting value: a new group should begin with an empty list, a set of tags should begin empty, or a record should start with zeroed fields. collections.defaultdict lets the dictionary create that initial value for you when you access a missing key with square brackets.
Group items as they arrive
Use list as the default factory when every key should collect a sequence of values. The factory is called separately for each new key, so different groups receive different lists.
Output
Ready to run.
Quick check
Why is defaultdict(list) useful when grouping records?
from collections import defaultdict
groups = defaultdict(list)
groups["east"].append("tea")
groups["west"].append("coffee")
print(groups["east"])
The general dictionary lessons cover ordinary lookup, insertion, and
get(). This lesson focuses on an automatic creation rule for repeated updates, especially when a program groups data as it processes it.
The factory runs for square-bracket lookup
defaultdict stores a callable in default_factory. When a missing key is requested with d[key], Python calls that factory with no arguments, stores the returned object under the key, and returns it. If the factory is None, the missing lookup raises KeyError as an ordinary dictionary does.
Output
Ready to run.
Quick check
What happens when items.get("unknown") is used for an absent key in a defaultdict(list)?
from collections import defaultdict
items = defaultdict(list)
print(items.get("unknown"))
print("unknown" in items)
That difference is important:
items["unknown"] is an operation that may mutate the mapping, while
items.get("unknown") merely performs an ordinary dictionary-style lookup. Do not use square brackets just to inspect whether a key might exist.
Choose the factory for the value you need
The factory can be any callable that takes no required arguments. list creates an empty list; set creates an empty set for collecting unique values. The set factory is useful when repeated values should be discarded within each group.
Output
Ready to run.
Quick check
Which factory fits a dictionary that stores unique tags for each project?
from collections import defaultdict
tags = defaultdict(set)
tags["docs"].add("python")
tags["docs"].add("python")
print(tags["docs"])
Create a fresh structured value per key
A small factory function can initialize a more structured value. Return a new object each time; do not return one shared mutable object from outside the factory, or separate keys could unexpectedly modify the same data.
Output
Ready to run.
Quick check
How is a default_factory used for a missing key?
from collections import defaultdict
def make_value():
return []
items = defaultdict(make_value)
items["x"].append(1)
print(items)
If calling the factory raises an exception, that exception propagates. The factory must match your value shape and should return a fresh mutable value for each key when independent state is required.
Choose defaultdict deliberately
Use defaultdict when missing-key access naturally means creating a new value for later mutation. Use dict.get() when you only need to read with a fallback and do not want to insert anything. The existing Counter lesson owns frequency counting; prefer Counter when the problem is tallying hashable items. A normal dictionary with setdefault() can also initialize one entry, but defaultdict often reads more clearly inside a repeated grouping loop.
Output
Ready to run.
Quick check
Which tool should normally be chosen to count occurrences of hashable items?
from collections import Counter
counts = Counter("level")
print(counts["e"])
Key takeaways
- Use list for grouped sequences, set for distinct values, or a callable that creates the structured value you need.
- A missing d[key] lookup calls default_factory and stores its result; get() and membership checks do not.
- Use defaultdict for automatic initialization, Counter for tallying, and ordinary dictionaries when lookup and insertion should stay explicit.
Quick check recap
Before moving on, explain when a new key should automatically create a value, why get() does not run the factory, and why each key needs an independent mutable object. Then complete the exercise and take the quiz.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.