Python has a tiny magic box called defaultdict. It lives in the collections module. It helps you avoid boring checks like “does this key exist?” before adding values. It is like a normal dictionary, but friendlier.
TLDR: defaultdict creates a default value when a missing key is used. For example, defaultdict(int) starts missing counts at 0, so counts["cat"] += 1 just works. In a small log analyzer with 10,000 rows, this can cut several lines of setup code and reduce key-check mistakes. Use it when your dictionary needs automatic lists, counts, sets, or nested data.
What Is defaultdict?
A normal Python dictionary gives you a KeyError if you ask for a missing key.
scores = {}
scores["Ada"] += 1 # KeyError
Ouch. The dictionary panics.
A defaultdict stays calm. It creates a value for you.
from collections import defaultdict
scores = defaultdict(int)
scores["Ada"] += 1
print(scores["Ada"]) # 1
The int function returns 0. So every new key starts at zero. Nice and tidy.
Think of it as a hotel receptionist for keys. If a guest does not have a room, it makes one.
How It Works
You create it like this:
defaultdict(default_factory)
The default_factory is a function that makes the default value.
intmakes0listmakes[]setmakesset()floatmakes0.0- A custom function can make anything
Now let’s see 15 practical examples. No wizard hat needed.
15 Practical Examples of Python defaultdict
1. Count Words
This is the classic example. Count how many times each word appears.
from collections import defaultdict
text = "cat dog cat bird dog cat"
counts = defaultdict(int)
for word in text.split():
counts[word] += 1
print(counts)
Missing words start at 0. Then they grow.
2. Group Names by First Letter
Use list when you want many items per key.
names = ["Alice", "Ben", "Anna", "Brian"]
groups = defaultdict(list)
for name in names:
groups[name[0]].append(name)
print(groups)
"A" gets Alice and Anna. "B" gets Ben and Brian.
3. Group Products by Category
This is common in shops and dashboards.
products = [
("apple", "fruit"),
("carrot", "vegetable"),
("banana", "fruit")
]
by_category = defaultdict(list)
for item, category in products:
by_category[category].append(item)
Now you can show products by shelf. Fruit party on aisle one.
4. Track Unique Visitors
Use set to avoid duplicates.
visits = [
("home", "u1"),
("home", "u2"),
("home", "u1"),
("about", "u3")
]
unique = defaultdict(set)
for page, user in visits:
unique[page].add(user)
print(unique["home"]) # {"u1", "u2"}
Even if u1 visits twice, they count once.
5. Build an Index
Search systems use indexes. You can build a tiny one.
docs = {
1: "python is fun",
2: "python is useful",
3: "cats are fun"
}
index = defaultdict(list)
for doc_id, text in docs.items():
for word in text.split():
index[word].append(doc_id)
print(index["python"]) # [1, 2]
Now each word points to document IDs.
6. Count Letters
Want to count characters? Same trick.
letters = defaultdict(int)
for char in "banana":
letters[char] += 1
print(letters)
Yes. Banana math is real.
7. Store Scores for Players
Each player can have a list of scores.
games = [
("Mia", 10),
("Leo", 7),
("Mia", 14)
]
scores = defaultdict(list)
for player, score in games:
scores[player].append(score)
print(scores["Mia"]) # [10, 14]
No need to create the list first.
8. Sum Sales by Region
Use float for money-like totals.
sales = [
("East", 19.99),
("West", 5.50),
("East", 8.25)
]
totals = defaultdict(float)
for region, amount in sales:
totals[region] += amount
Each region starts at 0.0.
9. Create Nested Dictionaries
Sometimes you need a dictionary inside a dictionary.
nested = defaultdict(lambda: defaultdict(int))
nested["store1"]["apples"] += 5
nested["store1"]["oranges"] += 2
print(nested["store1"]["apples"]) # 5
The outer key is created. Then the inner key is created. Smooth.
10. Build a Simple Graph
Graphs are nodes and links. Use lists for neighbors.
edges = [
("A", "B"),
("A", "C"),
("B", "D")
]
graph = defaultdict(list)
for start, end in edges:
graph[start].append(end)
print(graph["A"]) # ["B", "C"]
This is useful for maps, networks, and recommendation engines.
11. Reverse a Dictionary
Sometimes many keys share the same value.
people = {
"Amy": "admin",
"Bob": "user",
"Cara": "admin"
}
roles = defaultdict(list)
for name, role in people.items():
roles[role].append(name)
print(roles["admin"]) # ["Amy", "Cara"]
Now you can see who has each role.
12. Count File Extensions
This is handy for cleaning folders.
files = ["a.txt", "b.png", "c.txt", "d.pdf"]
ext_counts = defaultdict(int)
for filename in files:
ext = filename.split(".")[-1]
ext_counts[ext] += 1
print(ext_counts)
Your messy folder just got a tiny audit.
13. Group Errors by Type
Logs can be noisy. Grouping helps.
logs = [
("404", "/home"),
("500", "/checkout"),
("404", "/about")
]
errors = defaultdict(list)
for code, path in logs:
errors[code].append(path)
print(errors["404"])
If 40% of your errors are 404, this makes the problem easy to spot.
14. Make a Custom Default Value
You are not limited to built-in types.
def new_user():
return {"visits": 0, "paid": False}
users = defaultdict(new_user)
users["sam"]["visits"] += 1
print(users["sam"])
Each new user gets a starter profile. Very polite.
15. Build a Shopping Cart
A cart is perfect for defaultdict(int).
cart = defaultdict(int)
cart["apple"] += 3
cart["banana"] += 2
cart["apple"] += 1
print(cart["apple"]) # 4
No setup. Just add items. The cart behaves.
When Should You Use defaultdict?
Use it when missing keys should have a clear default value.
- Use
defaultdict(int)for counters. - Use
defaultdict(list)for grouping. - Use
defaultdict(set)for unique groups. - Use
defaultdict(float)for totals. - Use
lambdaor a function for custom defaults.
When Should You Avoid It?
defaultdict is helpful, but not always right.
A key is created when you access it. That can surprise you.
data = defaultdict(list)
print(data["ghost"])
print(data) # "ghost" now exists
If you only want to check a key, use in.
if "ghost" in data:
print(data["ghost"])
Also, if missing keys should be an error, use a normal dict. Errors can be useful. They are small alarms.
defaultdict vs dict.get()
You can also use dict.get().
counts = {}
counts["cat"] = counts.get("cat", 0) + 1
This works. But it gets repetitive.
defaultdict is cleaner when you do the same default action many times.
counts = defaultdict(int)
counts["cat"] += 1
Less typing. Fewer bugs. Happier fingers.
Final Thoughts
defaultdict is small, but mighty. It removes boring key checks. It makes counters, groups, indexes, carts, logs, and graphs easier to build.
Start with int, list, and set. Those cover many real jobs. Then try custom defaults when your data gets fancy.
Python will still not make your coffee. But with defaultdict, it will at least stop yelling about missing keys.
