Dictionaries
A dictionary (dict) stores data as key-value pairs. Instead of looking up a value by its numeric position, as you would with a list, you look it up by a key — a name, an id, a coordinate, anything hashable. Dictionaries are one of the most heavily used data structures in Python, powering everything from JSON payloads to function keyword arguments.
Creating a Dictionary
You can build a dict with curly-brace literal syntax using key: value pairs, or with the dict() constructor.
person = {"name": "Ada", "age": 36, "language": "Python"}
print(person) # {'name': 'Ada', 'age': 36, 'language': 'Python'}
# dict() constructor - handy with keyword arguments
person2 = dict(name="Grace", age=40, language="COBOL")
print(person2) # {'name': 'Grace', 'age': 40, 'language': 'COBOL'}
empty = {} # note: {} is an empty dict, not an empty set
print(type(empty)) # <class 'dict'>Keys Must Be Hashable
A dict key must be an immutable, hashable object — strings, numbers, and tuples all qualify. Lists (and other dicts, and sets) are mutable, so Python refuses to use them as keys: if the contents of a list could change after it was used as a key, its hash value would no longer match where it was stored, silently breaking the lookup. A tuple, being immutable, has a stable hash for its lifetime and works fine.
# Tuples work as keys because they're immutable
locations = {
(40.7128, -74.0060): "New York",
(51.5074, -0.1278): "London",
}
print(locations[(40.7128, -74.0060)]) # New York
# Lists are mutable, so they cannot be keys:
# bad = {[1, 2]: "value"} # TypeError: unhashable type: 'list'Accessing, Adding, Updating, and Deleting
Square-bracket syntax reads and writes a value for a given key. If the key already exists, assignment overwrites its value; if it does not, assignment creates a new entry. del removes a key entirely.
inventory = {"apples": 10, "bananas": 5}
print(inventory["apples"]) # 10 -- access
inventory["cherries"] = 20 # -- add a new key
inventory["apples"] = 15 # -- update an existing key
print(inventory) # {'apples': 15, 'bananas': 5, 'cherries': 20}
del inventory["bananas"] # -- delete a key
print(inventory) # {'apples': 15, 'cherries': 20}Safer Access with .get()
The .get() method looks up a key and returns None (or a default value you supply) instead of raising an error when the key is missing.
inventory = {"apples": 15, "cherries": 20}
print(inventory.get("apples")) # 15
print(inventory.get("mangoes")) # None -- no crash
print(inventory.get("mangoes", 0)) # 0 -- explicit default instead of NoneChecking Whether a Key Exists
Use the in operator to test for a key without triggering a KeyError. This checks keys only, not values.
inventory = {"apples": 15, "cherries": 20}
print("apples" in inventory) # True
print("mangoes" in inventory) # False
print(15 in inventory) # False -- 15 is a value, not a keyDictionaries Preserve Insertion Order
order = {}
order["first"] = 1
order["second"] = 2
order["third"] = 3
print(list(order.keys())) # ['first', 'second', 'third'] -- insertion order preservedNested Dictionaries
Dictionary values can themselves be dictionaries (or lists, or any object), which is how you model structured, JSON-like data in Python.
users = {
"u1": {"name": "Ada", "roles": ["admin", "editor"]},
"u2": {"name": "Grace", "roles": ["viewer"]},
}
print(users["u1"]["name"]) # Ada
print(users["u2"]["roles"][0]) # viewer
# Adding a new nested entry
users["u3"] = {"name": "Linus", "roles": ["contributor"]}
print(users["u3"]["name"]) # Linus
# Safely reading a deeply nested value that might not exist
roles = users.get("u4", {}).get("roles", [])
print(roles) # [] -- no KeyError even though "u4" doesn't existDict literals use
{key: value, ...};dict()accepts keyword arguments or an iterable of pairs.Keys must be hashable (immutable): strings, numbers, and tuples work; lists, dicts, and sets do not.
Use
.get()when a key might be missing; use[]only when you are certain the key exists.Insertion order is preserved and guaranteed since Python 3.7.