Python 字典合併全方法詳解|附初學者範例程式碼

1. 前言

Python 的字典(dict)是一種非常方便的資料結構,用來以鍵值對的形式管理資料。在實務中,常常會需要合併多個字典,例如整合多個設定檔,或是彙總來自不同資料集的資訊。

本文將詳細介紹在 Python 中合併字典的多種方法。內容涵蓋從初學者到中階使用者,包含基本技巧、Python 3.9 新增的寫法,甚至是應對特殊情況的進階技巧。我們會透過程式碼範例,幫助你了解每種方法的特性與使用場景,找到最適合自己的合併方式。

2. 字典合併的基本方法

在 Python 中,有多種方法可以用來合併字典。我們先從最基本的幾種方式開始介紹。

2.1 使用 update() 方法

特點

update() 方法是最基本的字典合併方式,會將另一個字典的內容加入到原本的字典中。這是一種破壞性操作(會改變原本的字典),因此若需要保留原始資料,使用時要特別注意。

程式碼範例

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

dict1.update(dict2)
print(dict1)  # {'a': 1, 'b': 3, 'c': 4}

說明

上述程式碼中,dict2 的內容被合併到 dict1。若有重複的鍵(例如 'b'),會以後面字典(這裡是 dict2)的值為主進行覆蓋。

適用情境

  • 不介意修改原本的字典。
  • 需要簡單且效率高的合併方法時。

2.2 使用解包運算子(**

特點

從 Python 3.5 起,可以使用解包運算子(**)來合併字典。這是一種非破壞性操作,會建立新的字典而不改變原始資料。

程式碼範例

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

combined_dict = {**dict1, **dict2}
print(combined_dict)  # {'a': 1, 'b': 3, 'c': 4}

說明

這個方法會將多個字典展開後合併為新的字典。若有重複的鍵,會使用後面字典(dict2)的值進行覆蓋。

適用情境

  • 需要保留原始字典內容。
  • 希望程式碼具有良好的可讀性。

2.3 使用合併運算子(|

特點

從 Python 3.9 開始,可以使用 | 運算子簡潔地合併字典。這也是非破壞性操作,會建立新的字典。

程式碼範例

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

combined_dict = dict1 | dict2
print(combined_dict)  # {'a': 1, 'b': 3, 'c': 4}

說明

這種寫法更加直觀,讓程式碼更易讀,也更適合 Python 初學者理解。

適用情境

  • 使用 Python 3.9 或以上版本時。
  • 希望程式碼簡潔且容易維護。

3. 特殊情況下的字典合併方式

在掌握基本的字典合併方法後,接下來我們來看看一些特殊情況或進階的合併技巧。這些方法在特定需求下非常實用,適合處理更複雜的場景。

3.1 使用 dict() 建構子

特點

這種方法是利用 dict() 建構子來合併多個字典。當你需要在合併時額外新增鍵值對,或是包含展開過的字典時,這種寫法會非常方便。

程式碼範例

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

combined_dict = dict(dict1, **dict2)
print(combined_dict)  # {'a': 1, 'b': 2, 'c': 3}

說明

  • dict1 作為基礎,dict2 的內容被展開後合併進來。
  • 注意:由於使用了 ** 運算子,dict2 的鍵必須是字串,否則會出錯。

適用情境

  • 在基本合併的同時想加入額外的鍵值對。
  • 需要 Python 3.5 或以上版本。

3.2 使用 collections.ChainMap

特點

ChainMap 是 Python 標準函式庫中 collections 模組提供的工具,適用於暫時性地整合多個字典。這種方式並不會真正合併字典,而是保留原始字典的結構。

程式碼範例

from collections import ChainMap

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

combined = ChainMap(dict1, dict2)
print(combined['b'])  # 2
print(combined['c'])  # 4

說明

  • ChainMap 可以將多個字典視為一個虛擬的整體。
  • 在查找鍵時,會優先從最前面的字典中搜尋。本例中,'b' 的值來自 dict1(值為 2)。

適用情境

  • 不希望實際合併字典,而是動態處理資料時。
  • 處理大量資料時,希望節省記憶體資源。

4. 合併字典時的注意事項

在合併字典的過程中,有幾個需要特別注意的地方。了解這些細節能幫助你避免錯誤與資料不一致的問題。

4.1 鍵值重複時的行為

當兩個字典中存在重複鍵時,合併後會以後面字典中的值為主,進行覆蓋。

範例

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

combined = {**dict1, **dict2}
print(combined)  # {'a': 1, 'b': 3, 'c': 4}

這個例子中,鍵 'b' 的值被 dict2 中的 3 覆蓋了原本 dict12。了解這種行為是非常重要的。

4.2 不同方法的效能差異

不同的合併方法在效能上可能會有所差異,特別是當資料量很大時,更需要注意選擇最合適的方式。

效能比較(概略)

  • update() 方法:效能高,但會改變原始字典,若需保留備份不適合。
  • 解包運算子(**:不會改變原始資料,較方便但在大量資料情況下記憶體使用可能增加。
  • ChainMap:不會真正合併資料,記憶體使用效率高,適合處理大量資料。
侍エンジニア塾

5. 各種字典合併方法的比較與選擇指南

這一節將比較不同的字典合併方法,幫助你根據實際情況選擇最合適的方式。

5.1 方法比較表

方法是否破壞原資料支援版本重複鍵的行為效能
update()破壞性所有版本以後方字典為主
解包運算子(**非破壞性3.5 以後以後方字典為主中等
合併運算子(|非破壞性3.9 以後以後方字典為主中等
ChainMap非破壞性所有版本以前方字典為主高(記憶體效率)

5.2 選擇建議

  • 如果使用的是 Python 3.9 或以上版本:
  • 推薦使用最簡潔且可讀性高的 | 運算子。
  • 如果使用的是 Python 3.5 到 3.8:
  • 可以選擇使用解包運算子(**)。
  • 若需要處理大量資料或重視記憶體使用效率:
  • ChainMap 是最佳選擇。
  • 若可以接受改變原始字典內容:
  • update() 方法是高效且簡單的方案。

6. 常見問題(FAQ)

本節將解答讀者在合併 Python 字典時常遇到的疑問,包括錯誤原因與特殊情境的對應方式。

6.1 為什麼在合併字典時會出現錯誤?

錯誤範例

執行以下程式碼時會發生錯誤:

dict1 = {'a': 1, 'b': 2}
dict2 = {('c',): 3}

combined_dict = {**dict1, **dict2}

錯誤原因

使用解包運算子(**)時,字典的鍵必須是字串。如果鍵是非字串型別(像是 tuple),就會出現錯誤。在上述範例中,dict2 的鍵 ('c',) 是 tuple,因此導致錯誤。

解決方法

如果鍵不是字串,可以改用 update() 方法,或使用迴圈手動合併:

dict1 = {'a': 1, 'b': 2}
dict2 = {('c',): 3}

dict1.update(dict2)  # 正常執行
print(dict1)  # {'a': 1, 'b': 2, ('c',): 3}

6.2 若使用的是 Python 3.9 以下版本,該如何替代 | 運算子?

解答

在 Python 3.9 以下的版本中雖然無法使用 | 運算子,但可以使用解包運算子(**)達到相同效果。

範例

即使是 Python 3.8 或更早的版本,也可以使用以下寫法:

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

combined_dict = {**dict1, **dict2}
print(combined_dict)  # {'a': 1, 'b': 3, 'c': 4}

6.3 若字典中包含巢狀結構,要如何合併?

問題說明

當合併的是巢狀字典時,單純使用 **| 會導致資料被覆蓋,而不是進行深層合併:

dict1 = {'a': {'x': 1}}
dict2 = {'a': {'y': 2}}

combined_dict = {**dict1, **dict2}
print(combined_dict)  # {'a': {'y': 2}}

如上例,dict2 的值覆蓋了 dict1 中的 'a' 鍵,導致原本的資料被移除。

解決方法

需要使用遞迴函式來進行深層合併:

def merge_dicts(d1, d2):
    result = d1.copy()
    for key, value in d2.items():
        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
            result[key] = merge_dicts(result[key], value)
        else:
            result[key] = value
    return result

dict1 = {'a': {'x': 1}}
dict2 = {'a': {'y': 2}}

combined_dict = merge_dicts(dict1, dict2)
print(combined_dict)  # {'a': {'x': 1, 'y': 2}}

6.4 可以一次合併多個字典嗎?

解答

在 Python 3.9 之後,你可以使用多個 | 運算子連續合併多個字典:

範例

dict1 = {'a': 1}
dict2 = {'b': 2}
dict3 = {'c': 3}

combined_dict = dict1 | dict2 | dict3
print(combined_dict)  # {'a': 1, 'b': 2, 'c': 3}

如果是舊版本,也可以使用多個解包運算子:

combined_dict = {**dict1, **dict2, **dict3}
print(combined_dict)  # {'a': 1, 'b': 2, 'c': 3}

6.5 處理大量資料時,哪種合併方式最有效?

解答

當資料量龐大時,使用 ChainMap 是一種高效選擇,因為它不會真正將字典合併,而是以串接方式進行查找,節省記憶體空間。

範例

from collections import ChainMap

dict1 = {'a': 1}
dict2 = {'b': 2}

combined = ChainMap(dict1, dict2)
print(combined['a'])  # 1
print(combined['b'])  # 2

7. 總結

本文介紹了在 Python 中合併字典的各種方法,從基本到進階,並搭配範例說明,讓初學者也能輕鬆理解。

重點回顧

  • update() 方法 是一種簡單且效率高的方式,但會改變原始字典。
  • 解包運算子(** 是非破壞性方法,適合建立新字典。
  • 合併運算子(| 適用於 Python 3.9 之後,語法簡潔且易讀。
  • ChainMap 適合處理大量資料,並具有優異的記憶體效率。

每種方法都有其優點與適用場景,建議根據實際需求與 Python 的版本來選擇。例如:若需處理巢狀結構、重複鍵、或大量資料,應特別考慮適合的合併策略。

未來在實際專案中遇到字典合併需求時,歡迎參考本文提供的方法,多嘗試實作將有助於加深理解。此外,也推薦閱讀本站其他與 Python 資料處理相關的教學內容!