Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Python

Use defaultdict and Counter for Cleaner Python Code

Learn how Python's defaultdict and Counter from the collections module eliminate boilerplate key-checking code, making dictionary handling cleaner, faster, and less error-prone.

July 2026 6 min read 2 views 0 hearts

Stop Wasting Time Checking for Keys in Python: Use defaultdict and Counter Instead

Ever written code like this?

word_count = {}
for word in sentence.split():
    if word not in word_count:
        word_count[word] = 0
    word_count[word] += 1

It works, but it's clunky. Every time you see a new word, you have to check if the key exists. Python gives us better tools for this. Let's look at two from the collections module that'll make your dictionary handling cleaner and faster.

defaultdict: The Key That Always Exists

defaultdict is like a regular dictionary, but when you try to access a key that doesn't exist, it automatically creates one with a default value. The magic happens when you define what kind of default you want.

Here's the same word counter using defaultdict:

from collections import defaultdict

word_count = defaultdict(int)
for word in sentence.split():
    word_count[word] += 1

That's it. No if checks. No KeyError. Clean and simple.

The int tells Python: "If a key's missing, create it with int() which returns 0." You can use other types too:

# Group items into lists
from collections import defaultdict

groups = defaultdict(list)
colors = [('red', 'apple'), ('yellow', 'banana'), ('red', 'strawberry')]
for color, fruit in colors:
    groups[color].append(fruit)

print(groups['red'])  # ['apple', 'strawberry']
print(groups['blue']) # [] (empty list, no error)

defaultdict(list) gives you an empty list for each new key. defaultdict(set) gives you a set. You can even pass a custom function:

from collections import defaultdict

def default_value():
    return {'count': 0, 'total': 0}

stats = defaultdict(default_value)
stats['apple']['count'] += 1
print(stats['apple'])  # {'count': 1, 'total': 0}

Counter: Counting Made Even Easier

When counting things is your main goal, Counter takes it a step further. It's built specifically for tallying items.

from collections import Counter

sentence = "the quick brown fox jumps over the lazy dog the dog"
word_count = Counter(sentence.split())
print(word_count)
# Counter({'the': 3, 'dog': 2, 'quick': 1, 'brown': 1, 'fox': 1, ...})

But Counter isn't just for words. Use it on any iterable:

# Count characters in a string
letter_freq = Counter("mississippi")
print(letter_freq)  # Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})

# Count dice rolls
rolls = [1, 4, 2, 6, 4, 2, 1, 4, 6]
roll_count = Counter(rolls)
print(roll_count.most_common(3))  # [(4, 3), (1, 2), (2, 2)]

most_common() is a gift. It returns items sorted by frequency, highest first. Perfect for finding the top 10 words in a document or the most popular items in a list.

Combining Them in Real Projects

At PythonSkillset, we often see defaultdict and Counter used together. Here's a common pattern for analyzing data:

from collections import defaultdict, Counter
import csv

# Read sales data and track total sales per product
with open('sales.csv', newline='') as f:
    reader = csv.reader(f)
    next(reader)  # skip header

    product_sales = defaultdict(float)
    for product, amount in reader:
        product_sales[product] += float(amount)

# Find best and worst sellers
top_products = Counter(product_sales).most_common(5)

Notice how we passed the defaultdict to Counter? It works because both behave like dictionaries. This is where Python's consistency pays off.

When to Use Each

  • defaultdict when you need to group items or build complex nested structures. Think: "I'll add to this list/key/value even if it's the first time."
  • Counter when counting is your core task and you might want frequency analysis. Think: "I need the top 5, and I want to see counts."
  • Both when you need default values for accumulation but also want to analyze frequencies later.

A Quick Pitfall to Avoid

defaultdict can hide bugs. If you access a nonexistent key by accident, it creates a default entry silently. This might lead to unexpected behavior later. For example:

d = defaultdict(int)
value = d['typo']  # Creates key 'typo' with value 0
print(d)  # defaultdict(<class 'int'>, {'typo': 0})

If you want to check for key existence without creating it, use key in d or d.get(key) instead.

Wrapping Up

You don't have to write verbose key-checking code anymore. Python's collections module gives you tools that handle the common patterns automatically. defaultdict removes the boilerplate of checking for missing keys, while Counter turns counting into a one-liner with built-in analysis.

Try rewriting your last project's dictionary handling with these. You'll write less code, reduce bugs, and make your intentions clearer. It's one of those small changes that makes Python feel truly elegant.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.