Dictionaries — Associative Data Storage
A **dictionary** is one of Python’s most powerful and flexible data structures.
Chapter 3: Data Structures
Sub-chapter: Dictionaries — Associative Data Storage
A dictionary is one of Python’s most powerful and flexible data structures.
It stores data as key-value pairs, allowing fast lookups, updates, and data mapping.
Think of a dictionary as a real-life dictionary — you look up a word (key) to find its definition (value).
🧠 Why Use Dictionaries?
Dictionaries are ideal for:
- ✅ Fast data access using unique keys (average O(1) lookup)
- 🧱 Mapping relationships (e.g., usernames → emails)
- 📦 Storing structured or JSON-like data
- 🧩 Flexible — values can be lists, tuples, or even nested dictionaries
⚙️ Creating Dictionaries
You can create a dictionary in several ways:
Using Curly Braces {}
person = {
"name": "Alice",
"age": 30,
"city": "New York"
}
Using dict() Constructor
user = dict(username="rambod", followers=1200)
Using zip()
keys = ["name", "age", "city"]
values = ["Bob", 25, "London"]
person = dict(zip(keys, values))
Empty Dictionary
data = {}
🎯 Accessing and Modifying Data
Access values using their keys:
print(person["name"]) # Alice
Modify or add new key-value pairs easily:
person["age"] = 31
person["email"] = "alice@example.com"
If you access a non-existent key with [], Python raises a KeyError.
Use .get() for safe access:
email = person.get("email", "Not found")
🧩 Dictionary Methods
| Method | Description | Example |
|---|---|---|
keys() | Returns all keys | person.keys() |
values() | Returns all values | person.values() |
items() | Returns key-value pairs | person.items() |
get(k, default) | Returns value or default if missing | person.get("name", "N/A") |
pop(k) | Removes and returns value for key | person.pop("age") |
update(d2) | Updates or merges another dictionary | person.update(new_data) |
clear() | Removes all key-value pairs | person.clear() |
Example:
contacts = {"Alice": "alice@mail.com", "Bob": "bob@mail.com"}
contacts["Charlie"] = "charlie@mail.com"
contacts.update({"David": "david@mail.com"})
removed = contacts.pop("Bob")
print(contacts)
print("Removed:", removed)
🧱 Dictionary Iteration
Dictionaries are iterable and allow multiple traversal methods.
person = {"name": "Alice", "age": 30, "city": "New York"}
for key in person:
print(key, "→", person[key])
for key, value in person.items():
print(f"{key}: {value}")
Iterate through only keys or values:
for name in contacts.keys(): print(name)
for email in contacts.values(): print(email)
⚙️ Dictionary Comprehensions
Just like list comprehensions, dictionaries have a concise syntax for building new dictionaries.
squares = {x: x**2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
With conditions:
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
🧩 Merging and Copying Dictionaries
Python 3.9+ introduced merge (|) and update (|=) operators.
a = {"x": 1, "y": 2}
b = {"y": 3, "z": 4}
merged = a | b
print(merged) # {'x': 1, 'y': 3, 'z': 4}
Shallow copy:
copy = a.copy()
🧠 Nested Dictionaries
Dictionaries can hold other dictionaries, creating structured or hierarchical data.
employees = {
"Alice": {"position": "Manager", "salary": 75000},
"Bob": {"position": "Developer", "salary": 60000}
}
print(employees["Alice"]["salary"]) # 75000
Add new nested entries:
employees["Charlie"] = {"position": "Designer", "salary": 65000}
🔍 Real-World Example — Student Database
Let’s build a simple student record management example using dictionaries.
students = {
101: {"name": "Alice", "grade": "A", "age": 20},
102: {"name": "Bob", "grade": "B", "age": 22},
103: {"name": "Charlie", "grade": "A", "age": 19}
}
# Retrieve student info
sid = 102
print(f"Student {sid}:", students.get(sid, "Not found"))
# Update a record
students[103]["grade"] = "A+"
# Add new record
students[104] = {"name": "David", "grade": "B+", "age": 21}
# Iterate through records
for sid, info in students.items():
print(f"ID {sid}: {info['name']} ({info['grade']})")
⚙️ Performance and Memory
Dictionaries are implemented as hash tables, meaning:
- Average lookup, insert, and delete time → O(1)
- Keys must be hashable (immutable types like strings, numbers, or tuples)
- Not guaranteed to preserve insertion order before Python 3.7 (but now they do)
⚡ For high-performance lookups and fast data retrieval, dictionaries are one of Python’s most efficient data types.
🧱 Comparing with Other Data Structures
| Feature | Dictionary | List | Set |
|---|---|---|---|
| Stores data as | Key-value pairs | Ordered values | Unique values |
| Lookup time | O(1) | O(n) | O(1) |
| Order preserved | ✅ (3.7+) | ✅ | ✅ (3.7+) |
| Mutable | ✅ | ✅ | ✅ |
| Duplicate keys/values | ❌ | ✅ | ❌ |
| Ideal for | Mapping relationships | Sequential storage | Membership tests |
🧠 Best Practices for Using Dictionaries
- Use
.get()instead of[]when key may not exist. - Avoid using mutable objects (like lists) as keys.
- Use dictionary comprehensions for clean data transformations.
- Use
.copy()or{**dict}to avoid modifying shared references. - For deep nested data, consider the
pprintmodule orjson.dumps()for readability.
🧩 Bonus: Pretty Printing JSON-like Dictionaries
import json
print(json.dumps(students, indent=4))
Output:
{
"101": {"name": "Alice", "grade": "A", "age": 20},
"102": {"name": "Bob", "grade": "B", "age": 22},
"103": {"name": "Charlie", "grade": "A+", "age": 19}
}
🧾 Key Takeaways
- Dictionaries store key-value pairs with O(1) average access time.
- Keys must be unique and immutable.
- Support powerful methods and comprehension syntax.
- Perfect for mapping structured or nested data.
- One of the most used and efficient Python data structures.
Mastering dictionaries is essential to writing elegant, efficient Python code — they form the backbone of data modeling, configuration systems, APIs, and countless real-world applications.