Skip to content

Python 容器:Dict & Set

之前的文章中已經介紹了兩種集合類型:List (列表) 和 Tuple (元組)。它們都是有序的序列,但在可變性上有所不同。

今天,將繼續探討 Python 內置的另外兩種強大的集合類型:Dictionary (字典) 和 Set (集合)。這兩種類型在處理非序列化、需要快速查找的數據時尤其有用。本文將重點介紹 Dictionary,因為它在日常編程中極為常用,然後再簡要說明 Set 的概念和用法。

📕 字典 (Dictionary)

Dictionary (簡稱 dict) 是 Python 中一種非常靈活的數據結構。它不按順序存儲元素,而是以 鍵-值對 (key-value pair) 的形式存儲數據。你可以把它想像成一本真實世界的字典,每個「單詞」(key) 都對應一個「解釋」(value)。

DictionaryList 一樣是可變的 (mutable),意味著你可以隨時新增、刪除或修改其中的元素。

創建一個 Dictionary

創建 Dictionary 非常簡單,主要使用大括號 {}

python
# 創建一個空的 Dictionary
empty_dict = {}
# 或者使用 dict() 函數
empty_dict_alt = dict()

print(empty_dict)       # Output: {}
print(type(empty_dict)) # Output: <class 'dict'>

# 創建一個帶有初始值的 Dictionary
student = {
    "name": "Chan Tai Man",
    "age": 20,
    "major": "Computer Science",
    "courses": ["CS101", "MATH203"]
}

print(student)
# Output: {'name': 'Chan Tai Man', 'age': 20, 'major': 'Computer Science', 'courses': ['CS101', 'MATH203']}

Key 的重要規則:

Dictionarykey 必須是不可變的 (immutable)。這意味著你可以使用 int, str, float, bool 甚至是 tuple 作為 key,但不能使用 list 或其他 dict 作為 key

python
# 合法的 key
valid_keys_dict = {
    1: "Integer key",
    "hello": "String key",
    (1, 2): "Tuple key"
}

# 不合法的 key (會引發 TypeError)
# invalid_keys_dict = {
#     [1, 2]: "List key" # TypeError: unhashable type: 'list'
# }

通常,key 的大小相對較小,而它指向的 value 可能是一個較大的 Object,但這並非硬性規定。

關於順序,自 Python 3.7 版本起,Dictionary 會記住元素的插入順序。但在舊版本中,Dictionary 是無序的。因此,一個好的編程習慣是不要依賴 Dictionary 的順序來實現你的邏輯。

存取、新增和修改元素

Dictionary 的操作圍繞著它的 key 進行。

python
student = {"name": "Chan Tai Man", "age": 20}

# 1. 存取元素 (Accessing)
# 使用方括號 [],如果 key 不存在會引發 KeyError
print(student["name"])  # Output: Chan Tai Man

# 使用 get() 方法更安全,如果 key 不存在,可以返回一個預設值 (預設是 None)
print(student.get("age"))        # Output: 20
print(student.get("gpa"))        # Output: None
print(student.get("gpa", "N/A")) # Output: N/A

# 2. 新增或修改元素 (Adding / Modifying)
# 如果 key 已存在,則更新 value
student["age"] = 21
print(student) # Output: {'name': 'Chan Tai Man', 'age': 21}

# 如果 key 不存在,則新增一個 key-value pair
student["major"] = "Computer Science"
print(student) # Output: {'name': 'Chan Tai Man', 'age': 21, 'major': 'Computer Science'}

移除元素

你可以使用 del 關鍵字或 pop() 方法來移除元素。

python
student = {"name": "Chan Tai Man", "age": 21, "major": "Computer Science"}

# 使用 del 關鍵字,如果 key 不存在會引發 KeyError
del student["major"]
print(student) # Output: {'name': 'Chan Tai Man', 'age': 21}

# 使用 pop() 方法,它會移除 key 並返回其 value
# 如果 key 不存在,可以提供一個預設值,否則會引發 KeyError
age = student.pop("age")
print(age)        # Output: 21
print(student)    # Output: {'name': 'Chan Tai Man'}

# popitem() 移除並返回最後插入的 (key, value) pair (Python 3.7+)
student = {"a": 1, "b": 2, "c": 3}
item = student.popitem()
print(item)     # Output: ('c', 3)
print(student)  # Output: {'a': 1, 'b': 2}

# clear() 清空整個 Dictionary
student.clear()
print(student) # Output: {}

檢查 Key 或 Value 是否存在

檢查 key 的存在性非常高效,而檢查 value 則需要遍歷整個 dict

python
student = {"name": "Chan Tai Man", "age": 21}

# 檢查 key 是否存在 (非常快)
print("name" in student)  # Output: True
print("major" in student) # Output: False

# 檢查 value 是否存在 (較慢,需要遍歷)
print(21 in student.values())             # Output: True
print("Computer Science" in student.values()) # Output: False

遍歷 Dictionary

最常用的遍歷方式是使用 for 循環和 items() 方法,它可以同時獲取 keyvalue

python
student = {"name": "Chan Tai Man", "age": 21, "major": "Computer Science"}

# 1. 遍歷所有的 key (預設行為)
print("--- Keys ---")
for key in student:
    print(key)

# 2. 遍歷所有的 value
print("\n--- Values ---")
for value in student.values():
    print(value)

# 3. 遍歷所有的 key-value pair (最常用)
print("\n--- Items (Key-Value pairs) ---")
for key, value in student.items():
    print(f"Key: {key}, Value: {value}")

Dictionary 的核心優勢:快速查找

Dictionary 最重要的用途是根據 key 快速查找 value。它的類似 Hash Table,查找、新增和刪除操作都很快。

相反 List 在查找元素時需要從頭到尾去搜索。

應用場景: 當你需要存儲一些臨時結果以備後用,或作為一種快取時,Dictionary 非常有用。

例如,計算一個複雜的數學函數,你可以將計算結果存儲在 dict 中,key 是函數的輸入,value 是計算結果。下次用相同的輸入調用函數時,直接從 dict 中讀取結果,避免重複計算。

合併與複製

合併 Merging

你可以用 update() 方法或 | 操作符(Python 3.9+)來合併兩個 dict

python
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

# 使用 update(),會修改 dict1
dict1_copy.update(dict2)
print(f"Updated dict1: {dict1_copy}") # Output: Updated dict1: {'a': 1, 'b': 3, 'c': 4}

# 使用 | 操作符 (Python 3.9+),會創建一個新的 dict
# 如果有重複的 key,後面的 dict 會覆蓋前面的
merged_dict = dict1 | dict2
print(f"Merged dict: {merged_dict}") # Output: Merged dict: {'a': 1, 'b': 3, 'c': 4}

複製 Copying

複製 dict 時需要注意淺複製 (shallow copy)深複製 (deep copy) 的區別。

  • 淺複製 (copy() 方法):創建一個新的 dict Object,但如果 value 是可變類型(如 list),它只會複製該 value 的引用,而不是 value 本身。
  • 深複製 (copy.deepcopy()):創建一個全新的 dict,並遞歸地複製所有嵌套的 Object。
python
import copy

original_dict = {
    'id': 1,
    'data': ['A', 'B']
}

# 1. 淺複製 (新字典和舊字典的 key 指向同一 Object)
shallow_copied_dict = original_dict.copy()
shallow_copied_dict['data'].append('C')

print(f"Original after shallow copy: {original_dict}")
# Output: Original after shallow copy: {'id': 1, 'data': ['A', 'B', 'C']}
# 注意:原始字典的 data 也被修改了!

# 2. 深複製 (新字典和舊字典的 key 不會指向同一 Object)
original_dict = { # 重置
    'id': 1,
    'data': ['A', 'B']
}
deep_copied_dict = copy.deepcopy(original_dict)
deep_copied_dict['data'].append('C')

print(f"Original after deep copy: {original_dict}")
# Output: Original after deep copy: {'id': 1, 'data': ['A', 'B']}
# 原始字典保持不變

Dictionary 常用方法總結

方法 (Method)描述 (Description)
d.keys()返回一個包含所有 key 的視圖 Object。
d.values()返回一個包含所有 value 的視圖 Object。
d.items()返回一個包含所有 (key, value) pair 的視圖 Object。
d.get(key, def)根據 key 獲取 value,若 key 不存在則返回 def(預設為 None)。
d.pop(key, def)移除指定的 key 並返回其 value,若不存在則返回 def
d.popitem()移除並返回最後插入的 (key, value) pair。
d.update(other_d)用另一個 dictkey-value pair 來更新當前的 dict
d.clear()清空 dict 中的所有元素。
d.copy()返回 dict 的一個淺複製。

🧩 集合 (Set)

Set (集合) 是另一個非常有用的數據結構。它的特點是:

  1. 無序 (Unordered):元素沒有固定的順序。
  2. 唯一 (Unique):不允許包含重複的元素。
  3. 可變 (Mutable):可以新增或刪除元素。

Set 不常用,但在需要處理唯一性或進行數學集合運算時,便會用到。

創建一個 Set

你可以用大括號 {}set() 函數來創建 set

python
# 使用大括號創建 set
# 注意: {} 中沒有冒號,不是字典,沒有 k/v 對
fruits = {"apple", "banana", "orange", "apple"} # 重複的 "apple" 會被自動忽略
print(fruits) # Output: {'orange', 'apple', 'banana'} (順序可能不同)

# 使用 set() 函數從 list 創建 set
numbers_list = [1, 2, 3, 2, 1, 4]
unique_numbers = set(numbers_list)
print(unique_numbers) # Output: {1, 2, 3, 4}

# 重要:創建一個空的 set 必須使用 set()
empty_set = set()
# empty_dict = {}  # 這會創建一個空的 dictionary!

基本操作

Set 的基本操作和 Dictionary 有些相似,但它沒有 key

python
s = {1, 2, 3}

# 獲取長度
print(len(s)) # Output: 3

# 檢查成員資格 (非常快)
print(2 in s) # Output: True
print(5 in s) # Output: False

# 新增元素
s.add(4)
s.add(2) # 再次新增 2 不會有任何效果
print(s) # Output: {1, 2, 3, 4}

# 移除元素
s.remove(3) # 元素不存在會有 KeyError
print(s) # Output: {1, 2, 4}

s.discard(5) # 元素不存在也不會錯誤,比較安全
print(s) # Output: {1, 2, 4}

數學集合運算

Set 最強大的功能是它支持高效的集合運算。

操作 (Operation)運算符 (Operator)方法 (Method)描述 (Description)
聯集 (Union)a | ba.union(b)返回包含 a 和 b 所有元素的新集合
交集 (Intersection)a & ba.intersection(b)返回 a 和 b 的共有元素的新集合
差集 (Difference)a - ba.difference(b)返回在 a 中但不在 b 中的元素
對稱差集 (Symmetric Difference)a ^ ba.symmetric_difference(b)返回只在 a 或 b 其中之一的元素
python
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# 聯集
print(f"Union: {set_a | set_b}") # Output: {1, 2, 3, 4, 5, 6}

# 交集
print(f"Intersection: {set_a & set_b}") # Output: {3, 4}

# 差集 (在 A 但不在 B)
print(f"Difference (A - B): {set_a - set_b}") # Output: {1, 2}

# 對稱差集 (只在其中一個集合的元素)
print(f"Symmetric Difference: {set_a ^ set_b}") # Output: {1, 2, 5, 6}

🤔 Dictionary vs Set:如何選擇?

了解了 dictset 後,你可能會問,在什麼情況下應該用哪一個?

  • 使用 Dictionary 當你:

    • 需要將數據(value)與一個唯一的標識符(key)關聯起來。
    • 數據是成對出現的,例如:用戶名對應用戶資料、配置項名稱對應配置值。
    • 需要基於 key 進行快速查找、更新或刪除操作。
  • 使用 Set 當你:

    • 只需要存儲一堆唯一的項目,而不需要關聯任何其他數據。
    • 最主要的操作是檢查一個項目是否存在於集合中。
    • 需要執行去重操作或集合運算(如聯集、交集)。

簡單來說:需要 key-value 結構,用 dict;只需要唯一的 value,用 set

📝 總結

DictionarySet 是 Python 中處理非序列化數據的兩大利器。Dictionary 以其高效的 key-value 查找能力,成為了程序員工具箱中最常用的數據結構之一。而 Set 則在處理唯一性和集合運算方面表現出色。

掌握這四種基本的集合類型 (List, Tuple, Dictionary, Set),並理解它們各自的優缺點和適用場景,是成為一個高效 Python 開發者的關鍵一步。希望這篇文章能幫助你更好地理解和運用它們!

📚 參考資料

KF Software House