Dictionaries
Dictionaries (dicts) are key-value stores that let you organize data by meaningful labels rather than numeric positions. Unlike lists and tuples that use indexes, dictionaries use keys to access values, making them perfect for representing structured data like user information, configuration settings, or any data where names matter more than position.
What are dictionaries?
A dictionary is an unordered collection of key-value pairs enclosed in curly braces {}. Dictionaries are:
- Key-value pairs: Data stored as
key: value - Unordered: Keys don't have a fixed position (in Python 3.7+, insertion order is preserved)
- Mutable: You can add, remove, or modify pairs after creation
- Unique keys: Each key can appear only once
- Fast lookups: Finding values by key is very efficient
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
scores = {'Alice': 95, 'Bob': 87, 'Charlie': 92}
Why this matters
Dictionaries are one of Python's most powerful and commonly used data structures. They're perfect for representing structured data where you need to access values by meaningful labels rather than numeric positions. Dictionaries excel at fast lookups, making them ideal for storing and retrieving data efficiently. You'll use dictionaries for configuration settings, user information, counting occurrences, grouping data, and mapping relationships. Their ability to associate keys with values makes code more readable and maintainable than using parallel lists or numeric indices. Understanding dictionaries is essential because they appear in nearly every Python application—from simple scripts to complex web frameworks and data processing pipelines.
Creating dictionaries
Empty dictionaries
Create an empty dictionary to add items later:
my_dict = {}
# or
my_dict = dict()
Dictionaries with items
Put key-value pairs inside curly braces, separated by commas:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
fruits = {'apple': 5, 'banana': 3, 'orange': 8}
Each pair has a key (before the colon) and a value (after the colon).
Using the dict() constructor
Create dictionaries using the dict() constructor:
# From key-value pairs
person = dict(name='Alice', age=30, city='Boston')
# From a list of tuples
items = [('name', 'Alice'), ('age', 30), ('city', 'Boston')]
person = dict(items)
The literal syntax {} is more common and Pythonic than using the dict() constructor.
Accessing values
Bracket notation
Access values using square brackets and the key:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
person['name'] # 'Alice'
person['age'] # 30
person['city'] # 'Boston'
Using variables as keys
Variables can be used as keys:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
key = 'name'
person[key] # 'Alice'
Key errors
Trying to access a key that doesn't exist raises a KeyError:
person = {'name': 'Alice', 'age': 30}
person['city'] # KeyError: 'city'
get() method
Use get() to safely access values without raising errors:
person = {'name': 'Alice', 'age': 30}
person.get('name') # 'Alice'
person.get('city') # None (key doesn't exist, returns None)
person.get('city', 'Unknown') # 'Unknown' (default value if key missing)
Modifying dictionaries
Adding or updating items
Use bracket notation to add new items or update existing ones:
person = {'name': 'Alice', 'age': 30}
# Update existing key
person['age'] = 31
# Add new key-value pair
person['city'] = 'Boston'
print(person) # {'name': 'Alice', 'age': 31, 'city': 'Boston'}
update()
Update multiple items at once:
person = {'name': 'Alice', 'age': 30}
person.update({'age': 31, 'city': 'Boston', 'job': 'Engineer'})
print(person) # {'name': 'Alice', 'age': 31, 'city': 'Boston', 'job': 'Engineer'}
You can also pass keyword arguments:
person = {'name': 'Alice', 'age': 30}
person.update(age=31, city='Boston')
Removing items
del statement
Remove a key-value pair using del:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
del person['city']
print(person) # {'name': 'Alice', 'age': 30}
pop()
Remove and returns a value:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
city = person.pop('city')
print(city) # 'Boston'
print(person) # {'name': 'Alice', 'age': 30}
# With default value if key doesn't exist
city = person.pop('city', 'Unknown') # Returns 'Unknown' if 'city' not found
popitem()
Remove and returns the last key-value pair (as a tuple):
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
item = person.popitem()
print(item) # ('city', 'Boston')
print(person) # {'name': 'Alice', 'age': 30}
clear()
Remove all items:
person = {'name': 'Alice', 'age': 30}
person.clear()
print(person) # {}
Nested dictionaries
Dictionaries can contain other dictionaries:
students = {
'Alice': {'age': 20, 'grade': 'A'},
'Bob': {'age': 21, 'grade': 'B'},
'Charlie': {'age': 19, 'grade': 'A'}
}
# Access nested values
print(students['Alice']['age']) # 20
print(students['Bob']['grade']) # 'B'
# Modify nested values
students['Alice']['age'] = 21
# Add nested dictionary
students['Diana'] = {'age': 20, 'grade': 'A'}
Dictionary keys and values
Valid keys
Keys must be hashable (immutable) types:
- Strings, numbers, tuples (with hashable elements), booleans,
None - Lists, dictionaries, and sets cannot be keys
# Valid keys
valid = {
'string': 1,
42: 'number',
(1, 2): 'tuple',
True: 'boolean',
None: 'none'
}
# Invalid keys
# invalid = {[1, 2]: 'list'} # TypeError: unhashable type: 'list'
# invalid = {{'a': 1}: 'dict'} # TypeError: unhashable type: 'dict'
Any values
Values can be any type, including mutable types:
mixed = {
'string': 'text',
'number': 42,
'list': [1, 2, 3],
'dict': {'nested': 'value'},
'tuple': (1, 2, 3)
}
Getting keys and values
keys()
Get all keys as a view object:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
keys = person.keys()
print(keys) # dict_keys(['name', 'age', 'city'])
# Convert to a list if needed
key_list = list(person.keys())
print(key_list) # ['name', 'age', 'city']
values()
Get all values as a view object:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
values = person.values()
print(values) # dict_values(['Alice', 30, 'Boston'])
# Convert to a list if needed
value_list = list(person.values())
print(value_list) # ['Alice', 30, 'Boston']
items()
Get all key-value pairs as tuples:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
items = person.items()
print(items) # dict_items([('name', 'Alice'), ('age', 30), ('city', 'Boston')])
# Convert to a list if needed
item_list = list(person.items())
print(item_list) # [('name', 'Alice'), ('age', 30), ('city', 'Boston')]
The keys(), values(), and items() methods return view objects that reflect changes to the dictionary. They're memory-efficient and update automatically.
Iterating over dictionaries
Iterating over keys (default)
By default, iterating over a dictionary gives you the keys:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
for key in person:
print(key)
# Output:
# name
# age
# city
This is equivalent to for key in person.keys():.
Iterating over keys explicitly
Use .keys() to make your intention clear:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
for key in person.keys():
print(key)
Iterating over values
Use .values() to iterate over values only:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
for value in person.values():
print(value)
# Output:
# Alice
# 30
# Boston
Iterating over key-value pairs
Use .items() to get both keys and values:
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
for key, value in person.items():
print(f"{key}: {value}")
# Output:
# name: Alice
# age: 30
# city: Boston
This uses tuple unpacking. Each item from .items() is a (key, value) tuple.
Practical iteration examples
scores = {'Alice': 95, 'Bob': 87, 'Charlie': 92}
# Find the highest score
max_score = 0
best_student = None
for name, score in scores.items():
if score > max_score:
max_score = score
best_student = name
print(f"{best_student} has the highest score: {max_score}")
# Calculate average score
total = 0
for score in scores.values():
total += score
average = total / len(scores)
print(f"Average score: {average}")
# Output:
# Alice has the highest score: 95
# Average score: 91.33333333333333
Common operations
Length
Get the number of key-value pairs with len():
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
print(len(person)) # 3
Membership testing
Check if a key exists using in:
person = {'name': 'Alice', 'age': 30}
'name' in person # True
'city' in person # False
'Alice' in person # False (checks keys, not values!)
To check if a value exists:
person = {'name': 'Alice', 'age': 30}
'Alice' in person.values() # True
Checking for key before access
person = {'name': 'Alice', 'age': 30}
# Safe access pattern
if 'city' in person:
city = person['city']
else:
city = 'Unknown'
# Or use get() for cleaner code
city = person.get('city', 'Unknown')
Useful dictionary methods
copy()
Create a copy of a dictionary:
original = {'name': 'Alice', 'age': 30}
copied = original.copy()
copied['age'] = 31
print(original) # {'name': 'Alice', 'age': 30} (unchanged)
print(copied) # {'name': 'Alice', 'age': 31}
Assigning a dictionary to another variable doesn't create a copy. Below both original and reference variables refer to the same dictionary:
original = {'name': 'Alice', 'age': 30}
reference = original # Not a copy!
reference['age'] = 31
print(original) # {'name': 'Alice', 'age': 31} (also changed!)
Use .copy() or dict() constructor to create a copy.
setdefault()
Get a value, or set a default if the key doesn't exist:
person = {'name': 'Alice', 'age': 30}
# Key exists: returns existing value
age = person.setdefault('age', 25)
print(age) # 30
print(person) # {'name': 'Alice', 'age': 30} (unchanged)
# Key doesn't exist: sets and returns default
city = person.setdefault('city', 'Unknown')
print(city) # 'Unknown'
print(person) # {'name': 'Alice', 'age': 30, 'city': 'Unknown'}
fromkeys()
Create a dictionary from keys with a default value:
# All values are None
keys = ['name', 'age', 'city']
person = dict.fromkeys(keys)
# {'name': None, 'age': None, 'city': None}
# All values are the same
person = dict.fromkeys(keys, 0)
# {'name': 0, 'age': 0, 'city': 0}
Common patterns
Building a dictionary incrementally
Start with an empty dictionary and add key-value pairs one at a time:
data = {}
data['name'] = 'Alice'
data['age'] = 30
data['city'] = 'Boston'
Counting occurrences
Use a dictionary to count how many times each item appears in a sequence:
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts) # {'apple': 3, 'banana': 2, 'orange': 1}
Grouping items
Organize items into groups based on a shared characteristic:
students = [
('Alice', 'Math'),
('Bob', 'Science'),
('Charlie', 'Math'),
('Diana', 'Science')
]
by_subject = {}
for name, subject in students:
if subject not in by_subject:
by_subject[subject] = []
by_subject[subject].append(name)
print(by_subject)
# {'Math': ['Alice', 'Charlie'], 'Science': ['Bob', 'Diana']}
Merging dictionaries
Combine multiple dictionaries into one using several different methods:
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
# Using update()
merged = dict1.copy()
merged.update(dict2)
# Using unpacking (Python 3.5+)
merged = {**dict1, **dict2}
# Using | operator (Python 3.9+)
merged = dict1 | dict2
Dictionary as a lookup table
Use dictionaries to map one value to another, like translating codes to descriptions:
grades = {
'A': 'Excellent',
'B': 'Good',
'C': 'Average',
'D': 'Below Average',
'F': 'Fail'
}
grade = 'B'
print(grades.get(grade, 'Unknown')) # 'Good'
Dictionary comprehensions
Create dictionaries using comprehensions (see comprehensions):
# Square each number
squares = {x: x**2 for x in range(5)} # See [ranges](./ranges) for more on range()
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Filter and transform
evens = {x: x*2 for x in range(5) if x % 2 == 0}
# {0: 0, 2: 4, 4: 8}
Best practices
- Use descriptive keys:
person['name']is clearer thanperson['n'] - Use
get()for safe access: AvoidsKeyErrorwhen keys might not exist - Use
.items()when you need both keys and values: More efficient than separate lookups - Prefer dictionary comprehensions: For creating dictionaries from sequences
- Be careful with copying: Use
.copy()when you need an independent copy - Use
infor key membership: Fast and readable
# Good: Descriptive keys and safe access
person = {'name': 'Alice', 'age': 30}
name = person.get('name', 'Unknown')
# Good: Using items() for iteration
for key, value in person.items():
print(f"{key}: {value}")
# Avoid: Accessing without checking
# name = person['name'] # KeyError if 'name' doesn't exist
# Better: Use get() with default
name = person.get('name', 'Unknown')
Summary
Dictionaries are powerful key-value stores:
- Access values by meaningful keys instead of numeric positions
- Fast lookups and efficient membership testing
- Support iteration over keys, values, or items
- Mutable and flexible data structures
- Perfect for representing structured, labeled data
Dictionaries are essential for organizing data by meaningful labels. They're particularly useful when you need to look up values by name rather than position, and they work seamlessly with loops to process key-value data efficiently.