Dictionaries are Python's most versatile data structure. They store key-value pairs, allowing you to organize and access data by meaningful names instead of numeric indices.
A dictionary maps keys to values:
person = {
"name": "Alice",
"age": 30,
"city": "New York"
}"name", "age", "city""Alice", 30, "New York"# Empty dictionary
empty = {}
With initial data
user = {
"username": "alice123",
"email": "alice@example.com",
"verified": True
}
Using dict()
settings = dict(theme="dark", volume=80, muted=False)
From pairs
pairs = [("a", 1), ("b", 2), ("c", 3)]
mapping = dict(pairs)
# {'a': 1, 'b': 2, 'c': 3}user = {"name": "Alice", "age": 30}
Using square brackets
print(user["name"]) # Alice
Safe access with get()
email = user.get("email") # Returns None if not found
print(email) # None
With default value
phone = user.get("phone", "Not provided")
print(phone) # Not providedWhen to use each:
dict[key] - when you're sure the key exists (crashes if missing)dict.get(key) - when key might not exist (returns None)dict.get(key, default) - when you want a specific defaultuser = {"name": "Alice"}
Add new key-value pair
user["email"] = "alice@example.com"
Update existing value
user["name"] = "Alice Smith"
Add multiple at once
user.update({"age": 30, "city": "NYC"})
print(user)
# {'name': 'Alice Smith', 'email': 'alice@example.com',
# 'age': 30, 'city': 'NYC'}user = {"name": "Alice", "age": 30, "temp": "delete me"}
Delete a key
del user["temp"]
Remove and get value
age = user.pop("age") # Returns 30
print(age)
Remove with default (doesn't crash if missing)
phone = user.pop("phone", None)
Remove last inserted item (Python 3.7+)
item = user.popitem() # Returns ("name", "Alice")
Clear everything
user.clear() # {}user = {"name": "Alice", "age": 30}
Check if key exists
if "email" in user:
print(user["email"])
else:
print("No email found")
Check if key doesn't exist
if "phone" not in user:
print("Phone number missing")
Get all keys
keys = user.keys() # dict_keys(['name', 'age'])
Get all values
values = user.values() # dict_values(['Alice', 30])user = {"name": "Alice", "age": 30, "city": "NYC"}
Loop through keys (default)
for key in user:
print(key)
Loop through values
for value in user.values():
print(value)
Loop through both (most common)
for key, value in user.items():
print(f"{key}: {value}")
Output:
# name: Alice
# age: 30
# city: NYCDictionaries can contain other dictionaries:
database = {
"user1": {
"name": "Alice",
"email": "alice@example.com",
"scores": [95, 87, 92]
},
"user2": {
"name": "Bob",
"email": "bob@example.com",
"scores": [88, 90, 85]
}
}
Access nested values
print(database["user1"]["name"]) # Alice
print(database["user2"]["scores"][0]) # 88
Add nested structure
database["user3"] = {
"name": "Charlie",
"email": "charlie@example.com"
}
Iterate nested structure
for user_id, user_data in database.items():
print(f"\n{user_id}:")
for field, value in user_data.items():
print(f" {field}: {value}")text = "the quick brown fox jumps over the lazy dog"
word_count = {}
for word in text.split():
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# {'the': 2, 'quick': 1, 'brown': 1, 'fox': 1, ...}
Or using dict.setdefault()
word_count = {}
for word in text.split():
word_count.setdefault(word, 0)
word_count[word] += 1students = [
{"name": "Alice", "grade": "A"},
{"name": "Bob", "grade": "B"},
{"name": "Charlie", "grade": "A"},
{"name": "David", "grade": "B"}
]Group by grade
by_grade = {}
for student in students:
grade = student["grade"]
if grade not in by_grade:
by_grade[grade] = []
by_grade[grade].append(student["name"])
print(by_grade)
# {'A': ['Alice', 'Charlie'], 'B': ['Bob', 'David']}original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print(inverted) # {1: 'a', 2: 'b', 3: 'c'}dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
Python 3.9+
merged = dict1 | dict2
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Older Python
merged = {**dict1, **dict2}
Using update (modifies original)
dict1.update(dict2)For automatic default values, use collections.defaultdict:
from collections import defaultdict
Automatically creates empty list for new keys
groups = defaultdict(list)
groups["A"].append("Alice")
groups["B"].append("Bob")
groups["A"].append("Alex")
No need to check if key exists!
print(dict(groups))
# {'A': ['Alice', 'Alex'], 'B': ['Bob']}
For counting
counts = defaultdict(int)
for letter in "hello":
counts[letter] += 1 # Starts at 0 automatically
print(dict(counts))
# {'h': 1, 'e': 1, 'l': 2, 'o': 1}For counting, use collections.Counter:
from collections import Counter
Count items
letters = Counter("mississippi")
print(letters)
Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
Most common items
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counts = Counter(words)
print(counts.most_common(2))
# [('apple', 3), ('banana', 2)]
Combine counters
c1 = Counter("aab")
c2 = Counter("abc")
print(c1 + c2) # Counter({'a': 3, 'b': 2, 'c': 1})Sets store unique values (no duplicates):
# Create a set
fruits = {"apple", "banana", "orange"}
Remove duplicates from list
numbers = [1, 2, 2, 3, 3, 3, 4]
unique = set(numbers) # {1, 2, 3, 4}
Add items
fruits.add("grape")
Remove items
fruits.remove("banana") # Crashes if not found
fruits.discard("kiwi") # Safe, doesn't crash
Set operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a & b) # Intersection: {3, 4}
print(a | b) # Union: {1, 2, 3, 4, 5, 6}
print(a - b) # Difference: {1, 2}
print(a ^ b) # Symmetric difference: {1, 2, 5, 6}Tuples are like lists but can't be changed:
# Create tuple
point = (10, 20)
rgb = (255, 128, 0)
Access items
x = point[0] # 10
Unpack tuple
x, y = point
r, g, b = rgb
Use as dictionary keys (lists can't do this)
locations = {
(0, 0): "origin",
(1, 0): "east",
(0, 1): "north"
}
print(locations[(1, 0)]) # east
Return multiple values from function
def get_stats():
return (10, 20, 30) # min, max, avg
min_val, max_val, avg_val = get_stats()users = {
"alice": {
"email": "alice@example.com",
"age": 30,
"premium": True,
"login_count": 150
},
"bob": {
"email": "bob@example.com",
"age": 25,
"premium": False,
"login_count": 45
}
}
Find all premium users
premium_users = [
username
for username, data in users.items()
if data["premium"]
]
print(premium_users) # ['alice']inventory = {
"laptop": {"price": 1200, "stock": 5},
"mouse": {"price": 25, "stock": 50},
"keyboard": {"price": 75, "stock": 30}
}
Check stock
item = "laptop"
if inventory[item]["stock"] > 0:
print(f"{item} available: ${inventory[item]['price']}")
else:
print(f"{item} out of stock")
Update stock
inventory["laptop"]["stock"] -= 1
Calculate total value
total_value = sum(
data["price"] * data["stock"]
for data in inventory.values()
)
print(f"Total inventory value: ${total_value}")config = {
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp"
},
"cache": {
"enabled": True,
"ttl": 3600
},
"logging": {
"level": "INFO",
"file": "/var/log/app.log"
}
}
Access nested config
db_host = config["database"]["host"]
cache_enabled = config["cache"]["enabled"]
Safe nested access
def get_config(path, default=None):
"""Get config using dot notation: 'database.host'"""
keys = path.split(".")
value = config
for key in keys:
if isinstance(value, dict) and key in value:
value = value[key]
else:
return default
return value
print(get_config("database.host")) # localhost
print(get_config("database.timeout", 30)) # 30 (default){"key": "value"}dict[key] or dict.get(key, default).items(), .keys(), or .values()defaultdict for automatic defaultsCounter for counting items