本文 AI 產出,尚未審核

Python 資料結構 – 字典(dict)

主題:get() 預設值


簡介

在日常開發中,**字典(dict)**是 Python 最常使用的資料結構之一。它以鍵(key)對應值(value)的方式儲存資料,查詢速度快、語法直觀。然而,當我們嘗試從字典取值時,如果鍵不存在就會拋出 KeyError,這在大量資料處理或使用者輸入時會造成程式中斷。

dict.get() 方法正是為了解決這類問題而設計的:它允許我們在鍵不存在時回傳預設值,而不是例外。掌握這個技巧不僅能寫出更健壯的程式,也能讓程式碼更簡潔、可讀性更高。本文將深入探討 get() 的用法、常見陷阱與最佳實踐,並提供多個實務範例,協助你在 Python 開發中善用這項功能。


核心概念

1. dict.get() 的基本語法

value = my_dict.get(key, default=None)
  • key:欲查詢的鍵。
  • default(可選):當鍵不存在時回傳的值,預設為 None
  • 回傳值:若 key 在字典中,回傳對應的值;否則回傳 default

小技巧:如果只傳入 key 而不提供 default,等同於 my_dict.get(key, None),此時仍不會拋出 KeyError

2. 為什麼不直接使用 my_dict[key]

# 可能拋出 KeyError
value = my_dict['missing_key']
  • 直接使用方括號存取會在鍵不存在時拋出例外,必須額外使用 try/exceptif key in my_dict 來防護。
  • get() 讓這類防護變得一行搞定,程式碼更為簡潔

3. default 可以是任意型別

default 不必是固定的值,任何 Python 物件皆可,例如:

  • 整數、字串、列表、集合、甚至函式或自訂類別的實例。
# 預設值為空列表
items = inventory.get('apple', [])

4. default 與可變物件的注意事項

default 為可變物件(如列表、字典),每次呼叫 get() 都會回傳同一個物件的參考。這在需要「每次都得到全新」的情況下會產生意外的共享狀態

# 錯誤示範:所有缺少的鍵會共用同一個列表
data = {}
data.setdefault('scores', []).append(95)   # 正確做法
# 若改用 get()
data.get('scores', []).append(88)          # 會拋錯,因為返回的是臨時列表

解決方案是使用 default_factory(如 collections.defaultdict)或在 get() 後自行建立新物件。


程式碼範例

下面提供 5 個實用範例,說明 get() 在不同情境下的運用方式。每個範例都附有說明註解,方便初學者快速理解。

範例 1:基本的預設值使用

# 建立一個簡單的字典
person = {'name': 'Alice', 'age': 30}

# 取出已存在的鍵
name = person.get('name')          # -> 'Alice'

# 取出不存在的鍵,提供預設值
city = person.get('city', 'Taipei')   # -> 'Taipei'

print(f"{name} lives in {city}.")

說明city 不在 person 中,get() 直接回傳 'Taipei',避免了 KeyError


範例 2:使用 None 作為預設值(最常見)

# 假設從 API 取得的資料可能缺少某些欄位
api_response = {'id': 123, 'status': 'ok'}

# 直接使用 get(),若欄位缺失回傳 None
error_msg = api_response.get('error')
if error_msg is None:
    print("No error, continue processing.")
else:
    print(f"Error: {error_msg}")

技巧None 常被用來表示「未提供」或「無值」的情況,配合 if value is None 判斷即可。


範例 3:預設值為可變物件(列表)

# 記錄每個使用者的購物車內容
carts = {
    'alice': ['book', 'pen'],
    # bob 尚未有購物車
}

# 取得 bob 的購物車,若不存在則給一個空列表
bob_cart = carts.get('bob', [])
bob_cart.append('notebook')   # 只會在本次變數上加入

print(carts)   # {'alice': ['book', 'pen'], 'bob': []}
print(bob_cart)  # ['notebook']

注意:此範例使用 get() 的返回值 不會寫回 carts,若需要同步,需要自行賦值回字典,或改用 setdefault()


範例 4:與 setdefault() 結合,避免共享可變物件

from collections import defaultdict

# 使用 defaultdict 讓每個缺少的鍵自動得到一個新列表
scores = defaultdict(list)

# 為不同學生加入分數
scores['alice'].append(85)
scores['bob'].append(92)

print(scores)   # defaultdict(<class 'list'>, {'alice': [85], 'bob': [92]})

說明defaultdict 內部實作類似 dict.get(key, default_factory()),每次缺少的鍵都會得到全新的列表,避免共享問題。


範例 5:在資料清理時使用 get() 取代多層 if

raw_data = [
    {'id': 1, 'name': 'Tom', 'score': 78},
    {'id': 2, 'name': 'Jerry'},                # 缺少 score
    {'id': 3, 'name': 'Spike', 'score': 92},
]

# 我們想把每筆資料轉成 (id, name, score) 三元組,若缺少 score 則給 0
cleaned = [(d['id'], d['name'], d.get('score', 0)) for d in raw_data]

print(cleaned)
# [(1, 'Tom', 78), (2, 'Jerry', 0), (3, 'Spike', 92)]

優點:使用 get() 讓列表生成式保持單行,程式碼更易讀且不易出錯。


常見陷阱與最佳實踐

陷阱 說明 建議的做法
使用可變物件作為 default 每次呼叫 get() 都會回傳同一個物件的參考,導致資料意外被共享。 若需要每次得到新物件,改用 setdefault()defaultdict 或在 get() 後自行 copy()
忽略 defaultNone 的情況 有時會誤以為 None 代表「有值」的情況,導致後續程式誤判。 明確檢查 is None,或在設計時使用特殊 sentinel 物件(如 object())作為預設值。
get()in 檢查混用 兩者同時使用會降低效能,且失去 get() 的簡潔性。 只要需要值就使用 get(),只需要判斷鍵是否存在則使用 key in dict
對不存在的鍵使用 dict[key] 會拋出 KeyError,破壞程式流程。 使用 get()setdefault(),除非你確定鍵一定存在。
在大型迴圈中頻繁呼叫 dict.get() default 為耗時運算,會影響效能。 可先將 default 計算結果儲存變數,或使用 defaultdict 讓字典自行產生。

最佳實踐小結

  1. 預設值盡量使用不可變物件(如 None0""),避免共享狀態。
  2. 需要自動建立新容器時,優先考慮 defaultdictsetdefault()
  3. 若僅需判斷鍵是否存在,使用 if key in my_dict:,不要混用 get()
  4. 在函式或類別的參數預設值,避免直接寫 dict.get(key, []),改用 default_factory 或在函式內部處理。

實際應用場景

1. API 回傳資料的容錯處理

當呼叫外部服務時,回傳的 JSON 可能缺少某些欄位。使用 get() 可在不拋例外的情況下提供安全的預設值,讓後續資料處理流程順暢。

response = {
    "user_id": 42,
    "profile": {"nickname": "Bob"}
    # 可能缺少 "email"
}
email = response.get("email", "unknown@example.com")

2. 統計計算中的計數器

在計算詞頻、點擊次數等統計時,常用字典累加值。get() 能簡化「不存在則從 0 開始」的寫法。

words = ["apple", "banana", "apple", "orange", "banana", "apple"]
freq = {}
for w in words:
    freq[w] = freq.get(w, 0) + 1
print(freq)   # {'apple': 3, 'banana': 2, 'orange': 1}

3. 配置檔的預設值

開發大型系統時,常把設定寫在字典或 json 檔中。若使用者未提供某些設定項,get() 可快速補上預設值,避免程式在啟動時失敗。

config = {
    "host": "localhost",
    "port": 8080
    # 沒有 "debug"
}
debug_mode = config.get("debug", False)

4. 資料清理與轉換

在 ETL(Extract‑Transform‑Load)流程中,資料欄位可能不完整。利用 get() 可一次完成缺失值填補與型別轉換。

raw = {"id": "001", "price": "12.5"}   # price 可能是字串或缺失
price = float(raw.get("price", 0.0))

總結

dict.get() 是 Python 中 防止 KeyError、提供預設值 的利器。透過本篇文章,你應該已了解:

  • get() 的基本語法與返回行為。
  • 為什麼在多數情況下它比直接索引更安全、更簡潔。
  • 可變物件作為預設值時的共享問題與解決方案(defaultdictsetdefault())。
  • 多個實務範例,從基礎查詢、API 容錯、統計計數到設定管理,都能看到 get() 的身影。
  • 常見的陷阱與最佳實踐,讓你寫出更健全、易維護的程式碼。

掌握 get() 後,你的字典操作將變得 更具彈性更具可讀性,也能在面對不確定或缺失資料時,保持程式的穩定性。未來在開發任何需要鍵值查詢的功能時,請先思考是否可以使用 dict.get() 取代繁瑣的 if 判斷或 try/except,讓程式碼更乾淨、效能更佳。祝你寫程式愉快,持續探索 Python 的無限可能!