Dictionaries and sets organize data differently from lists. Instead of accessing items by position, you access them by key. This makes lookups fast and your code more expressive.
Creating dictionaries
A dictionary stores key-value pairs. Keys must be unique and immutable; values can be anything:
user = {
"name": "Ada",
"age": 36,
"role": "admin",
}
empty = {} # empty dict
config = dict(host="localhost", port=8080) # alternative syntax
The keys are strings in most everyday code, but any immutable type works:
point_labels = {(0, 0): "origin", (1, 2): "point A"}
Accessing values
Use square brackets with a key to access a value:
user["name"] # "Ada"
user["age"] # 36
Accessing a key that does not exist raises a KeyError:
user["email"] # KeyError: 'email'
Use .get() to safely access a key with a fallback:
user.get("email") # None — no error
user.get("email", "N/A") # "N/A" — custom default
Modifying dictionaries
Dictionaries are mutable — you can add, change, and remove entries:
user = {"name": "Ada", "age": 36}
user["email"] = "ada@example.com" # add a new key
user["age"] = 37 # update an existing key
del user["role"] # remove a key
removed = user.pop("age") # remove and return value
Common dictionary methods:
user.keys() # dict_keys(['name', 'age', 'email'])
user.values() # dict_values(['Ada', 37, 'ada@example.com'])
user.items() # dict_items([('name', 'Ada'), ('age', 37), ...])
user.get("name") # "Ada" — safe access
user.setdefault("role", "user") # returns existing or sets default
user.update({"city": "London"}) # merge another dict
Iterating over dictionaries
Iterating directly yields keys:
for key in user:
print(key, user[key])
Iterating over items is more common and clearer:
for key, value in user.items():
print(f"{key}: {value}")
Checking for keys
Use in to check if a key exists:
if "email" in user:
print(user["email"])
This checks keys, not values. To check values, use in on .values():
if "admin" in user.values():
print("User is an admin.")
Dictionary merging
In Python 3.9+, use | to merge dictionaries:
defaults = {"theme": "light", "lang": "en"}
overrides = {"theme": "dark"}
config = defaults | overrides
# {"theme": "dark", "lang": "en"}
The right side wins for duplicate keys. Use |= to update in place:
defaults |= overrides
# defaults is now {"theme": "dark", "lang": "en"}
In older versions, use .update() or {**defaults, **overrides}.
Sets
A set is an unordered collection of unique items:
colors = {"red", "green", "blue"}
numbers = set([1, 2, 2, 3, 3]) # {1, 2, 3} — duplicates removed
empty = set() # empty set — {} creates an empty dict, not a set
Sets are useful for:
- removing duplicates from a collection
- membership testing (faster than lists for large collections)
- mathematical set operations like union and intersection
Set operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # {1, 2, 3, 4, 5, 6} — union
a & b # {3, 4} — intersection
a - b # {1, 2} — difference (in a but not b)
a ^ b # {1, 2, 5, 6} — symmetric difference (in either, not both)
Common set methods:
a.add(5) # add an item
a.remove(3) # remove an item (KeyError if missing)
a.discard(99) # remove an item (no error if missing)
a.pop() # remove and return an arbitrary item
a.clear() # remove all items
When to use each data structure
Use a list when:
- order matters
- you need to access items by position
- duplicates are meaningful
log_entries = ["error", "warning", "error", "info"]
Use a tuple when:
- you have a fixed structure with a known number of fields
- each position means something specific
user_record = ("Ada", 36, "admin")
Use a dictionary when:
- you need to look up values by name or key
- you are modeling a thing with named attributes
- you need fast lookups
user = {"name": "Ada", "age": 36, "role": "admin"}
Use a set when:
- you need to track unique items
- you need to test membership efficiently
- you need to find overlaps or differences between collections
seen_ids = set() # track which IDs we have processed
active_users = {1, 3, 5}
banned_users = {3, 7}
at_risk = active_users & banned_users # {3} — overlap
What to carry forward
- dictionaries store key-value pairs —
{"key": "value"} - use
dict[key]for direct access; use.get()for safe access - dictionaries are mutable — add, update, and remove entries
- iterate with
.items()to get key-value pairs - sets store unique items and support union, intersection, difference
- use
set()(not{}) to create an empty set - choose the data structure based on how you will access and use the data
These four structures — lists, tuples, dictionaries, and sets — are the foundation for organizing data in Python. The next lesson covers comprehensions, a concise way to build and transform collections.