在Python中合併字典模塊ChainMap的隱藏坑

在Python中,當咱們有兩個字典須要合併的時候,可使用字典的update方法,例如:python

a = {'a': 1, 'b': 2}
b = {'x': 3, 'y': 4}
a.update(b)
print(a)
複製代碼

運行效果以下圖所示:微信

然而,這個方法有一個問題——它會改變其中一個字典。若是咱們不想改變原有的兩個字典,那麼咱們必須要單獨再建立一個字典:spa

a = {'a': 1, 'b': 2}
b = {'x': 3, 'y': 4}
c = dict(a)
c.update(b)
print(c)
print(a)
複製代碼

若是原來的兩個字典很是大,那麼這種方式將會浪費大量的內存。3d

不管是直接修改原有的其中一個字典,仍是建立另外一個字典,這兩種方案都有點缺陷。那麼有沒有既不修改原有字典,又不另外建立一個新的字典的方法呢?code

答案就是collections模塊下面的ChainMapcdn

使用ChainMap能夠把多個字典合併成一個ChainMap對象。讀寫這個對象就像是讀字典同樣。對象

例如:blog

from collections import ChainMap
a = {'a': 1, 'b': 2}
b = {'x': 3, 'y': 4}
c = ChainMap(a, b)
print(c['a'])
print(c['y'])
複製代碼

運行效果以下圖所示:內存

不只能夠「合併」兩個字典,ChainMap能夠接受任意多個字典,並把他們全都合在一塊兒:string

from collections import ChainMap
a = {'a': 1, 'b': 2}
b = {'x': 3, 'y': 4}
c = {'z': 5, 'w': 6}
d = {'m': 7, 'h': 8, 'k': 9}
e = ChainMap(a, b, c, d)
print(e['a'], e['y'], e['z'], e['k'])
複製代碼

運行效果以下圖所示:

ChainMap不會真的把字典合併在一塊兒,而是在內部儲存一個Key到每一個字典的映射,當你讀取e[key]的時候,它先去查詢這個key在哪一個字典裏面,而後再去對應的字典裏面查詢對應的值。因此使用ChainMap幾乎不須要額外的內存空間(當前這個對象本身會佔用一些空間,可是若是要合併大字典,那麼它本身佔用的空間幾乎能夠忽略)。

因此你是否是以爲使用ChainMap就能實現完美合併字典了呢?

在使用它以前,你必定要理解它的運行原理。若是你理解了它的運行原理,那麼下面幾個問題,你在運行代碼以前就會知道結果是什麼:

  1. 若是兩個字典裏面有一個Key的名字相同,那麼使用ChainMap之後會讀取哪個?
  2. 若是爲ChainMap對象添加一個Key-Value對,那麼這個值會添加到哪裏?
  3. 若是從原字典裏面刪除一個Key,ChainMap對象裏面的Key也會消失嗎?
  4. 若是從ChainMap對象裏面刪除一個Key,那麼原字典裏面的Key會消失嗎?

首先來講第一個問題的答案:

ChainMap對象會使用第一個擁有這個Key的字典裏面的值,以下圖所示:

第二個問題,新的Key-Value會被添加進第一個字典裏面,以下圖所示:

第三個問題,若是修改了原來的字典,那麼ChainMap對象也會相應更新:

第四個問題,若是這個Key只在一個源字典中存在,那麼這個Key會被從源字典中刪除。若是這個Key在多個字典中都存在,那麼Key會被從第一個字典中刪除。當被從第一個字典中刪除之後,第二個源字典的Key能夠繼續被ChainMap讀取。

以上4點,在你使用ChainMap的時候必定要牢記,不然可能會致使你發現不了的Bug。

若是這篇文章對你有幫助,請關注個人微信公衆號: 未聞Code(ID: itskingname),第一時間獲的最新更新:

相關文章
相關標籤/搜索