訂單不是一行扁平的資料:它有明細,每條明細還有加料。想一步跳到底,KeyError 就是這麼來的。應該先檢查哪一層?
真實資料很少能塞進一個列表或字典裡。訂單包含商品,介面回應包含物件,記錄包含欄位。給每一層命名,並一次只存取一層,巢狀資料就會清楚很多。 你還會逐層驗證、把巢狀記錄攤平成行,並用顯式堆疊走訪樹。
字典組成的列表
外層列表儲存多條記錄,每個字典儲存一條記錄的欄位。走訪列表,再從每個字典裡讀取鍵。很多 JSON 檔案都是這種形狀。
orders = [
{"drink": "latte", "price": 4.5},
{"drink": "tea", "price": 3.0},
]
for order in orders:
print(order["drink"], order["price"])列表中的記錄
讀取巢狀鍵
每一層用一對方括號。data["shop"] 回傳內層字典,再用 ["name"] 讀取欄位。路徑變長時,可以先把中間結果存進變數。
data = {"shop": {"name": "Corner", "open": True}}
print(data["shop"]["name"])
print(data["shop"]["open"])兩層鍵
更新欄位並計算總和
巢狀值仍然是普通的字典值,所以賦值方式不變。要對某個欄位求和,就走訪外層列表,從每條記錄裡讀取該鍵。能用迴圈表達意圖時,不要硬編碼索引。
orders = [{"price": 3.0}, {"price": 4.5}]
orders[0]["price"] = 3.5
total = sum(order["price"] for order in orders)
print(total)更新並求和
每一層都要驗證
巢狀讀取是一串假設。每一層都檢查容器型別和鍵,或者先用 get() 給空預設值再索引。在邊界做一次驗證,比從三個地方分別接住 TypeError 和 KeyError 便宜。
payload = {"shop": {"name": "Corner", "orders": [{"total": 9.0}]}}
shop = payload.get("shop", {})
orders = shop.get("orders", []) if isinstance(shop, dict) else []
first_total = orders[0].get("total") if orders and isinstance(orders[0], dict) else None
print(shop.get("name", "unknown"))
print(first_total)
print(payload.get("missing", {}).get("name", "unknown"))先檢查容器,再讀鍵
把巢狀記錄攤平成行
巢狀訂單適合儲存,卻不適合直接匯報。一次攤平一層:外層訂單、內層商品,再生成同時帶兩個標識的行。缺失值要顯式保留,不要悄悄丟掉整行。
orders = [
{"id": 1, "items": [{"name": "latte", "qty": 2}]},
{"id": 2, "items": [{"name": "tea", "qty": 1}, {"name": "mocha", "qty": 3}]},
]
rows = []
for order in orders:
for item in order.get("items", []):
rows.append((order["id"], item["name"], item.get("qty", 0)))
for row in rows:
print(row)每層一個迴圈,保留父級 id
用顯式堆疊走訪樹
巢狀可能很深時,顯式堆疊能避開遞迴深度限制,也讓待處理的工作看得見。想從左到右存取,就按相反順序壓入子節點;堆疊是後進先出。
tree = {"name": "menu", "children": [
{"name": "drinks", "children": [{"name": "latte"}, {"name": "tea"}]},
{"name": "food", "children": [{"name": "toast"}]},
]}
stack = [tree]
while stack:
node = stack.pop()
print(node["name"])
stack.extend(reversed(node.get("children", [])))堆疊儲存還沒處理的工作
本課要點
- 巢狀資料要一層一層地用方括號讀取。
- 字典列表是常見的記錄集合。
- 給內層字典的鍵賦值,就能更新欄位。
- 用迴圈或生成器表達式匯總某個欄位。
- 巢狀資料每層都要驗證;顯式堆疊讓樹走訪更可控。
常見錯誤
- 值還是字典時,只寫了一層方括號。
- 不檢查記錄,就假設每條記錄都有同樣的鍵。
- 硬編碼索引,而不是走訪記錄。
- 子節點壓入堆疊的順序反了,卻奇怪輸出為什麼倒過來。
建立兩個訂單字典,放進列表,然後列印總價。
動手試試
改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。
練習本課
12 道題,作答後立即看到解釋。