Dictionaries are one of Python's most powerful and versatile data structures. Their key-value pair system allows for flexible and efficient solutions to many common programming problems. Let's explore some key use cases.
Dictionaries are perfect for modeling real-world objects or structured data, much like JSON objects in web development. Each key represents an attribute, and the value is the data for that attribute.
# A dictionary representing a user's profile
user_profile = {
"user_id": 101,
"username": "alex_coder",
"email": "alex@example.com",
"is_active": True,
"permissions": ["read", "write"]
}
# Accessing data is intuitive
print(f"Username: {user_profile['username']}")
print(f"Permissions: {user_profile['permissions'][0]}")
This is much more readable and manageable than using lists or tuples, where you'd have to remember the index of each piece of data.
A classic use case for dictionaries is to count the occurrences of items in a sequence. The item becomes the key, and its count becomes the value.
text = "hello world"
char_counts = {}
for char in text:
# Use .get() to handle the first time a character is seen
char_counts[char] = char_counts.get(char, 0) + 1
print(char_counts)
# Output: {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
Pro Tip: For this specific task, Python's standard library provides a specialized dictionary subclass: collections.Counter
.
from collections import Counter
text = "hello world"
char_counts = Counter(text)
print(char_counts)
# Output: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
Dictionaries can act as a cache to store the results of expensive computations. This technique, called memoization, prevents re-calculating results for the same inputs, dramatically improving performance.
# A cache to store previously computed Fibonacci numbers
fib_cache = {}
def fibonacci(n):
# If the value is in the cache, return it
if n in fib_cache:
return fib_cache[n]
# Base cases
if n <= 1:
return n
# Compute it, store it in the cache, and then return it
result = fibonacci(n - 1) + fibonacci(n - 2)
fib_cache[n] = result
return result
# The calculation for 35 would be very slow without memoization
print(f"Fibonacci(35) = {fibonacci(35)}")
print(f"Cache content (partial): {{... '35': {fib_cache[35]}}}")
You can use a dictionary to group items from a list based on a common property. The property becomes the key, and the value is a list of all items sharing that property.
students = [
{"name": "Alice", "grade": "A"},
{"name": "Bob", "grade": "B"},
{"name": "Charlie", "grade": "A"},
{"name": "David", "grade": "C"},
{"name": "Eve", "grade": "B"},
]
grades = {}
for student in students:
grade = student["grade"]
# .setdefault() initializes the key with an empty list if it's not present
grades.setdefault(grade, []).append(student["name"])
print(grades)
# Output: {'A': ['Alice', 'Charlie'], 'B': ['Bob', 'Eve'], 'C': ['David']}
Answer: There are two common ways. The update()
method modifies one dictionary in place, while the dictionary unpacking syntax (**
) creates a new dictionary. If there are overlapping keys, the value from the second dictionary will overwrite the first.
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
# Method 1: Using update()
merged_dict1 = dict1.copy() # Use copy to avoid modifying the original
merged_dict1.update(dict2)
print(f"Using update(): {merged_dict1}") # {'a': 1, 'b': 3, 'c': 4}
# Method 2: Using dictionary unpacking (Python 3.5+)
merged_dict2 = {**dict1, **dict2}
print(f"Using unpacking: {merged_dict2}") # {'a': 1, 'b': 3, 'c': 4}
d[key]
and d.get(key)
?Answer: The key difference is in error handling.
d[key]
(bracket notation): This directly accesses the key. If the key does not exist, it raises a KeyError
.d.get(key, default=None)
: This method attempts to get the key. If the key doesn't exist, it returns a default value (which is None
if not specified) instead of raising an error.You should use d.get()
when you are not sure if a key exists and you want to handle its absence gracefully without a try...except
block.
d = {'a': 100}
# Using bracket notation
print(d['a']) # Works fine, prints 100
# print(d['b']) # Would raise a KeyError
# Using .get()
print(d.get('a')) # Prints 100
print(d.get('b')) # Prints None (default value)
print(d.get('b', 0)) # Prints 0 (specified default)
Answer: You can use the max()
function with a custom key
argument. The key argument should be a function that tells max()
what to compare. In this case, we tell it to compare the dictionary's values by using d.get
.
scores = {'math': 95, 'science': 98, 'history': 88}
# The key=scores.get tells max() to look at the values, not the keys
top_subject = max(scores, key=scores.get)
print(f"The subject with the highest score is: {top_subject}")
# Output: The subject with the highest score is: science