天天看點

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

前言

集合是專門的容器資料類型(Container Datatype),可以替代Python的通用内置容器,如dict、list、set和tuple。容器是一種特殊用途的對象,可用于存儲不同的對象。它提供了一種通路所包含對象并周遊它們的方法。

Python提供了實作容器資料類型的collections子產品。在章節系列中,我們将學習集合子產品中的不同類型集合融洽,其中包括:

  1. ChainMap
  2. Counter
  3. Deque
  4. DefaultDict
  5. NamedTuple
  6. OrderedDict
  7. UserDict
  8. UserList
  9. UserString
Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

下面就來分别介紹這些容器類型——鍊式映射(ChainMap)。

認識ChainMap

Python的所提供的ChainMap類(就稱為鍊映射類),是個類似字典(dict)的類,用于快速連結許多個映射,以便将它們作為單個單元處理。它通常比建立一個新字典并運作多個update()調用要快得多。

其文法格式如下:

xchainMap = collections.ChainMap(*maps)

說明:文法格式中的collections是導入的完成子產品名稱。如果這樣導入該子產品:import collections as cts,則文法可變為:class cts.ChainMap(*maps),或則模糊導入:from collections import ChainMap,這樣可以修改為:ChainMap(*maps)。

ChainMap可将多個字典或其他映射組合在一起,建立一個單一的、可更新的視圖(字典清單)。如果沒有指定映射,則提供一個空字典,以便新的鍊式映射(ChainMap)總是至少有一個映射可以。

鍊映射的底層映射存儲在一個清單中。該清單是公共的,可以使用maps屬性來通路或更新。除了maps屬性,鍊映射沒有其他的新擴充狀态。

ChainMap是通過引用來合并底層映射的。是以,如果其中一個底層映射得到更新,這些更改也将反映在ChainMap中。

鍊映射支援所有常用的字典(dict)方法。此外,還有一個maps屬性,用于建立新子上下文的方法,并且除了第一個映射,屬性maps可用于通路所有映射——maps是個清單。

對應一個使用者可更新的映射清單,該清單從第一次搜尋到最後一次搜尋是有序的。它是唯一存儲的狀态,可以通過修改來更改要搜尋的映射。這樣的清單應該始終至少包含一個映射。

來看下面的簡單示例,代碼清單如下:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

運作程式輸出結果如下:

ChainMap({'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'})

[{'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'}]

上述清單中,我們用兩個字典定義一個ChainMap對象(chain_map)。然後我們列印輸出ChainMap對象和maps屬性。正如在輸出中看到的,結果是這些字典的構成視圖。

通路ChainMap的鍵值

我們可以通過使用keys()和values()方法來通路ChainMap的鍵和值。代碼示例如下:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

上述代碼輸出結果為:

KeysView(ChainMap({'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'}))

ValuesView(ChainMap({'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'}))

如程式輸出結果所示,chain_map.keys()的結果是一個KeysView(鍵視圖),chain_map.values()的結果是一個ValuesView(值視圖)。這兩個視圖類型内置類,都是可疊代對象,可以分别周遊相應的鍵名和值對象。例如:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

輸出結果為:

key = a,value=A

key = b,value=B

key = one,value=1

key = two,value=2

鍊映射包含的值為:

A;B;1;2;

結合代碼和輸出結果,很容易了解,即鍊式映射就是把多個映射(map有很多實作,字典是其中的一種)打包成一個映射即鍊式映射,然後可以像操作字典樣操作通路。比如像字典一樣這樣來通路某個鍵的值:

print(chain_map['b'] )

也就是通過使用鍵名:chain_map[' one ']來通路ChainMap底層字典中單個項的值。

為ChainMap添加新映射

ChainMap可以包含任意數量的字典。我們使用内置的new_child()方法向ChainMap添加新字典。new_child()方法傳回一個新的ChainMap,其中包含着新映射,後跟目前執行個體中的所有映射。這裡需要注意的一點是,新添加的字典将放在ChainMap的開頭。來看示例:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

運作程式,輸入結果如下:

Old: ChainMap({'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'})

New: ChainMap({'x': 0, 'y': 1}, {'one': 1, 'two': 2}, {'a': 'A', 'b': 'B'})

這裡需要注意的是,用鍊式映射的new_child()方法添加新字典後,不改變原來的鍊映射,會傳回一個新的ChainMap對象。另外,如果你修改鍊式映射所包含的映射或字典,變化也将展現在鍊式映射對象中。

另外,實踐中要當心:如果你按照字典操作來添加新的鍵值對,則該鍵值對會添加到鍊式映射所包含的第一個映射中,如:new_chain_map['X'] = 'Unkown' 。自己動手試試看。

所含映射有相同鍵怎麼辦?

底層上,鍊式映射主要是為把多個字典或映射打包成一個映射,以便集中操作。如果所辦函的字典中有相同的鍵會怎樣呢?來看示例:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

運作程式輸出結果如下:

ChainMap({'id': 21001, 'country': '大秦', 'emperor': '嬴政'}, {'name': '李靖', 'country': '大唐', 'title': '元帥'})

大秦

('name', '李靖')

('country', '大秦')

('title', '元帥')

('id', 21001)

('emperor', '嬴政')

很顯然,連結的映射中出現相同字典項時,隻讀取第一個,以第一個為準,而且當你更新一個鍵的值時,它也隻是更新第一個映射内容的鍵值。

如果你想一次更新所有映射中的相同鍵的值怎麼辦呢?你可以自定義一個ChainMap子類來實作,或定義更新方法。因為ChainMap中有個屬性maps持有完整的各個映射,可以基于此屬性來完成相同鍵的一次性更新。這裡簡單給個通過方法的方式實作多映射相同鍵的一次更新。示例代碼如下:

Python程式設計:換種方式用字典之鍊式映射(ChainMap),盤它

當然,你可以寫得更複雜一點,以完成更多的需要,也可實作一次多個映射中的相同鍵的值。自己動手試試吧。

本文小結

本文主要介紹了Python集合子產品中的鍊式映射容器——ChainMap的使用,可以把多個字典打包成一個對象來操作。同時需要注意的是,該映射隻是對原字典的引用,當你修改原字典時,相應的變化也為展現在鍊式映射中。同時,在為ChainMap新增新的鍵值對時,它會添加到所包含的第一個映射對象中。

就寫這些了,程式設計學習最好的方法就是多寫代碼,自己試試手吧^_*

最後,記得點贊+關注,前進不迷路——轉發分享出去吧,謝謝[666]