Python Dictionaries — Methods & Advanced Patterns
Dictionaries are one of Python's most versatile data structures. This tutorial goes beyond basics into advanced patterns used in production code.
Learning Objectives
- Master all built-in dictionary methods
- Understand dictionary merging strategies (Python 3.9+)
- Work with nested dictionaries and complex data shapes
- Use defaultdict, Counter, and ChainMap effectively
Dictionary Methods Reference
person = {"name": "Alice", "age": 30, "city": "NYC"}
# Access methods
person.get("name") # "Alice"
person.get("salary", 0) # 0 (default if key missing)
person.keys() # dict_keys(['name', 'age', 'city'])
person.values() # dict_values(['Alice', 30, 'NYC'])
person.items() # dict_items([('name', 'Alice'), ...])
# Modification
person.update({"age": 31, "email": "alice@example.com"})
person.setdefault("phone", "N/A") # Sets only if key missing
person.pop("city") # Removes and returns value
person.popitem() # Removes last inserted item
# Copying
shallow = person.copy()
from_dict = dict(person)
Merging Dictionaries
# Python 3.9+ — the best way
defaults = {"color": "blue", "size": "medium", "verbose": False}
user_prefs = {"color": "red", "verbose": True}
config = defaults | user_prefs
# {'color': 'red', 'size': 'medium', 'verbose': True}
# Python 3.5+ unpacking
config = {**defaults, **user_prefs}
# .update() — modifies in place
config = defaults.copy()
config.update(user_prefs)
Nested Dictionary Access
data = {
"user": {
"profile": {
"name": "Alice",
"addresses": {
"home": {"street": "123 Main St", "city": "NYC"},
"work": {"street": "456 Office Blvd", "city": "NYC"}
}
}
}
}
# Safe nested access
def deep_get(d, *keys, default=None):
for key in keys:
if isinstance(d, dict):
d = d.get(key, default)
else:
return default
return d
street = deep_get(data, "user", "profile", "addresses", "home", "street")
# "123 Main St"
Dictionary Comprehensions
# Create dict from two lists
names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 91]
grade_book = {name: score for name, score in zip(names, scores)}
# Filter and transform
passed = {k: v for k, v in grade_book.items() if v >= 90}
# Swap keys and values
reversed_dict = {v: k for k, v in grade_book.items()}
# Invert with grouping
from collections import defaultdict
by_score = defaultdict(list)
for name, score in grade_book.items():
by_score[score].append(name)
Performance Tips
# Membership testing: dict is O(1), list is O(n)
valid_users = {"alice", "bob", "charlie"} # Use set for lookup
"alice" in valid_users # Fast
# Use dict for frequency counting
text = "the cat sat on the mat the cat"
from collections import Counter
word_freq = Counter(text.split())
# Counter({'the': 3, 'cat': 2, 'sat': 1, 'on': 1, 'mat': 1})
# sorted() on dicts
sorted_by_key = dict(sorted(grade_book.items()))
sorted_by_value = dict(sorted(grade_book.items(), key=lambda x: x[1], reverse=True))
Key Takeaways
- Use
|operator for merging (Python 3.9+) - Use
get()for safe access with defaults - Dict comprehensions are faster than loops
defaultdictandCountersolve common patterns- Dicts maintain insertion order (Python 3.7+)