Records inside records
Real records nest: an order has a customer dictionary and a list of line dictionaries. Each pair of brackets goes one level deeper: order["customer"]["city"].
- Read a value two levels down, one lookup at a time
- Loop over a list of dictionaries stored under a key, and total it
- Update an inner value in place, and tell a KeyError from a TypeError when you take a wrong turn
An order from an online shop is not flat. It has a customer (a record with a city and a state) and several lines (each with a SKU, a quantity and a price). In Python that is a dictionary whose values include another dictionary and a list of dictionaries, the same shape that web APIs send as JSON.
Read it one step at a time. order["customer"] is the inner dictionary, so order["customer"]["city"] is its city. order["items"] is a list, so you loop over it.
Run each example to see what it prints. Running examples doesn't count toward progress.
order = {
"order_id": "O104839",
"customer": {"customer_id": "C00800", "city": "Miami", "state": "FL"},
"items": [
{"sku": "ELE-24781", "quantity": 1, "unit_price": 51.49},
{"sku": "HOM-22847", "quantity": 2, "unit_price": 31.0},
],
}
print(order["customer"]["city"])
print(len(order["items"]), "lines")
subtotal = 0
for line in order["items"]:
subtotal = subtotal + line["quantity"] * line["unit_price"]
print(f"{order['order_id']} to {order['customer']['state']}: {subtotal:.2f}")order = {"order_id": "O104839", "items": [{"sku": "ELE-24781", "quantity": 1}]}
print(order["items"]["sku"])Nested values can be changed in place. Reach the inner dictionary, then store into it. A catalogue keyed by product ID with a small record for each product is a common shape. Selling one unit changes only that product's stock.
catalogue = {
"P0035": {"name": "Deluxe Pillow", "price": 47.99, "stock": 4},
"P0146": {"name": "Nordic Handbook", "price": 15.99, "stock": 0},
}
catalogue["P0035"]["stock"] = catalogue["P0035"]["stock"] - 1
catalogue["P0146"]["price"] = 12.99
for product_id, product in catalogue.items():
status = "in stock" if product["stock"] > 0 else "sold out"
print(product_id, product["name"], product["price"], status)When to use it: for records that contain other records, such as API responses, orders with lines, or catalogues of products. Mistakes to avoid:
- Using a key on a list. Loop over the list first.
- Guessing the shape. Print the outer value to see whether the next level is a dictionary or a list.
- Forgetting that a missing key at any level raises KeyError.
- A value in a dictionary can be another dictionary or a list. Read it one lookup at a time.
- Loop over a list of dictionaries, and look keys up in each one.
- A key used on a list raises TypeError, and a missing key at any level raises KeyError.
- Next module: put these steps into functions you can name, call and test.