The dictionary is Python's most powerful built-in data structure. It stores data as key–value pairs with near-instant lookups, and it powers everything from JSON to function keyword arguments to object attributes under the hood. Knowing dictionaries deeply makes you a dramatically more effective Python programmer.
This deep-dive covers creating and accessing dictionaries, the safe get() pattern, updating and deleting, iterating, dictionary comprehensions, merging, nested dictionaries, and the high-value helpers defaultdict and Counter. Every example is runnable with output.
Creating Dictionaries
Keys must be hashable (strings, numbers, tuples); values can be anything. Since Python 3.7, dictionaries keep insertion order.
person = {"name": "Tushar", "age": 25} # literal
empty = {} # empty dict
from_pairs = dict([("a", 1), ("b", 2)]) # from pairs
from_kwargs = dict(x=10, y=20) # from keywords
print(person)
print(from_pairs)
print(from_kwargs)
Output:
{'name': 'Tushar', 'age': 25}
{'a': 1, 'b': 2}
{'x': 10, 'y': 20}
Accessing Values: [] vs get()
Square brackets raise KeyError if the key is missing. get() returns None (or a default you supply) instead — safer for optional keys.
person = {"name": "Tushar", "age": 25}
print(person["name"]) # 'Tushar'
print(person.get("email")) # None (no error)
print(person.get("email", "n/a")) # default value
# print(person["email"]) # KeyError!
Output:
Tushar
None
n/a
Adding, Updating, and Removing
d = {"a": 1}
d["b"] = 2 # add
d["a"] = 99 # update
d.update({"c": 3, "a": 0}) # bulk add/update
print(d)
removed = d.pop("b") # remove and return its value
print("popped:", removed, "->", d)
d.setdefault("z", 100) # add only if missing
print(d)
Output:
{'a': 99, 'b': 2, 'c': 3}
popped: 2 -> {'a': 0, 'c': 3}
{'a': 0, 'c': 3, 'z': 100}
Iterating Over a Dictionary
Use .keys(), .values(), and .items() — the last gives you key and value together.
scores = {"math": 90, "science": 85, "art": 95}
for subject, score in scores.items():
print(f"{subject}: {score}")
print("keys:", list(scores.keys()))
print("max subject:", max(scores, key=scores.get))
Output:
math: 90
science: 85
art: 95
keys: ['math', 'science', 'art']
max subject: art
Dictionary Comprehensions
Build dictionaries in one line with {key: value for ...}.
nums = [1, 2, 3, 4]
squares = {n: n * n for n in nums}
print(squares)
prices = {"apple": 3, "banana": 1, "cherry": 5}
cheap = {k: v for k, v in prices.items() if v < 4}
print(cheap)
Output:
{1: 1, 2: 4, 3: 9, 4: 16}
{'apple': 3, 'banana': 1}
Merging Dictionaries
Python 3.9+ has the clean | merge operator; earlier versions use {**a, **b}. The right-hand dict wins on key clashes.
defaults = {"theme": "light", "lang": "en"}
user = {"lang": "fr", "font": "serif"}
merged = defaults | user # 3.9+
print(merged)
merged2 = {**defaults, **user} # works on older versions too
print(merged2)
Output:
{'theme': 'light', 'lang': 'fr', 'font': 'serif'}
{'theme': 'light', 'lang': 'fr', 'font': 'serif'}
Nested Dictionaries
Values can be dictionaries themselves — the natural shape for JSON-like data.
users = {
"u1": {"name": "Tushar", "roles": ["admin"]},
"u2": {"name": "Asha", "roles": ["editor"]},
}
print(users["u1"]["name"])
print(users["u2"]["roles"][0])
Output:
Tushar
editor
Power Tools: defaultdict and Counter
The collections module supercharges dictionaries. defaultdict auto-creates missing values; Counter tallies items instantly.
from collections import defaultdict, Counter
# Group words by their first letter
words = ["apple", "avocado", "banana", "cherry", "blueberry"]
groups = defaultdict(list)
for w in words:
groups[w[0]].append(w) # no KeyError on first access
print(dict(groups))
# Count occurrences
votes = ["yes", "no", "yes", "yes", "no"]
print(Counter(votes))
print(Counter(votes).most_common(1))
Output:
{'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}
Counter({'yes': 3, 'no': 2})
[('yes', 3)]
Real-World Example: Word Frequency Counter
text = "the quick brown fox the lazy dog the end"
freq = {}
for word in text.split():
freq[word] = freq.get(word, 0) + 1 # classic get-default pattern
# Top 2 most frequent
top = sorted(freq.items(), key=lambda kv: kv[1], reverse=True)[:2]
print(freq)
print("top:", top)
Output:
{'the': 3, 'quick': 1, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1, 'end': 1}
top: [('the', 3), ('quick', 1)]
Common Mistakes to Avoid
- Using
[]for optional keys — useget()to avoidKeyError. - Unhashable keys — lists/dicts can't be keys; use tuples for compound keys.
- Modifying a dict while iterating it — iterate over
list(d.items())instead. - Assuming no order — dicts preserve insertion order since 3.7, but don't rely on sorting; sort explicitly.
- Reinventing counting/grouping — reach for
Counteranddefaultdict.
Summary Table
| Operation | Code |
|---|---|
| Safe access | d.get(key, default) |
| Add / update | d[key] = v / d.update(...) |
| Remove | d.pop(key) / del d[key] |
| Iterate pairs | for k, v in d.items(): |
| Comprehension | {k: v for ...} |
| Merge | a | b (3.9+) |
| Count / group | Counter / defaultdict |
Conclusion
Dictionaries give you fast, expressive key–value storage. Master get() for safe access, items() for iteration, comprehensions for building, | for merging, and Counter/defaultdict for counting and grouping — and you'll handle most real-world data tasks with ease.
Next time you find yourself writing if key in d: ... else: ..., see whether get(), setdefault(), or a defaultdict would say it more cleanly.
π¬ Comments (0)
No comments yet. Be the first to share your thoughts!