Python defaultdict Explained with 15 Practical Examples

July 28, 2026

jonathan

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.

  • int makes 0
  • list makes []
  • set makes set()
  • float makes 0.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 lambda or 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.

Also read: