Learning objectives
Model records with the right Python types, write explicit control flow, and reject invalid data early.
Core model
Python data pipelines commonly move between dict, list, tuple, set, and typed scalar values. Choose types by semantics: tuples for fixed records, sets for membership, and dictionaries for named fields.
order = {"order_id": 1001, "quantity": 2, "unit_price": 39.90, "status": "paid"}
allowed = {"paid", "refunded", "cancelled"}
if order["status"] not in allowed:
raise ValueError(f"invalid status: {order['status']}")
gross_amount = order["quantity"] * order["unit_price"]
Prefer guard clauses over deeply nested branches. Never silently coerce a value when invalid input should stop the pipeline.
Lab
Download the orders dataset. Write validate_order(record) that rejects non-positive quantities for paid orders, missing IDs, and unknown statuses.
Checkpoint
Why is a set a better fit than a list for allowed? What should happen to a cancelled order with quantity zero?
Reference solution
def validate_order(row):
required = {"order_id", "quantity", "status"}
if missing := required - row.keys():
raise ValueError(f"missing fields: {sorted(missing)}")
if row["status"] not in {"paid", "refunded", "cancelled"}:
raise ValueError("unknown status")
if row["status"] == "paid" and int(row["quantity"]) <= 0:
raise ValueError("paid quantity must be positive")
return row