2017-07-28 58 views
0

我正在尋找關於我的Python代碼的反饋。我正在試圖合併兩本字典。其中一個字典控制結構和默認值,第二個字典將在適用時覆蓋默認值。以1字典爲基礎合併Python中的字典

請注意,我要尋找以下行爲:

  • 鍵只存在於其他字典應該加入
  • 嵌套類型的字典,應考慮到

我寫了這個簡單的功能:

def merge_dicts(base_dict, other_dict): 
    """ Merge two dicts 

    Ensure that the base_dict remains as is and overwrite info from other_dict 
    """ 
    out_dict = dict() 
    for key, value in base_dict.items(): 
     if key not in other_dict: 
      # simply use the base 
      nvalue = value 
     elif isinstance(other_dict[key], type(value)): 
      if isinstance(value, type({})): 
       # a new dict myst be recursively merged 
       nvalue = merge_dicts(value, other_dict[key]) 
      else: 
       # use the others' value 
       nvalue = other_dict[key] 
     else: 
      # error due to difference of type 
      raise TypeError('The type of key {} should be {} (currently is {})'.format(
       key, 
       type(value), 
       type(other_dict[key])) 
      ) 
     out_dict[key] = nvalue 
    return out_dict 

我相信這可以做得更漂亮/ pythonic。

+0

的'值鍵不在'base_dict'中。這是想要的行爲? –

+0

因此''other_dict'中不在'base_dict'中的鍵應該被忽略,對吧? – jdehesa

+1

問題不是重複的,至少不是這些問題;這裏必須考慮嵌套的字典。 – jdehesa

回答

1

「Pythonicness」是評估一個硬的措施,但這裏是我對此採取:

def merge_dicts(base_dict, other_dict): 
    """ Merge two dicts 

    Ensure that the base_dict remains as is and overwrite info from other_dict 
    """ 
    if other_dict is None: 
     return base_dict 
    t = type(base_dict) 
    if type(other_dict) != t: 
     raise TypeError("Mismatching types: {} and {}." 
         .format(t, type(other_dict))) 
    if not issubclass(t, dict): 
     return other_dict 
    return {k: merge_dicts(v, other_dict.get(k)) for k, v in base_dict.items()} 

實例:other_dict`不會,如果相應的增加

merge_dicts({"a":2, "b":{"b1": 5, "b2": 7}}, {"b": {"b1": 9}}) 
>>> {'a': 2, 'b': {'b1': 9, 'b2': 7}} 
+0

這裏的一個很好的例子是「if other_dict是None」,但爲什麼不使用:「if not other_dict」? – user1934514

+0

@ user1934514老實說,我假設'other_dict'永遠不會包含'None',我不確定它是否適合您的情況。然而,我猜'0','False',''''''或'[]'是太有效的值,所以我避免將它們丟棄爲「None」而不是僅僅檢查其「falsy」值(「None」值當'k'不存在時,預計來自前一個堆棧調用中的'other_dict.get(k)')。 – jdehesa

1

如果你正在使用Python 3.5或更高版本,你可以簡單地做:

merged_dict = {**base_dict, **other_dict} 

如果你使用任何先前版本,你可以用update方法做到這一點:

merged_dict = {} 
merged_dict.update(base_dict) 
merged_dict.update(other_dict) 

欲瞭解更多信息,你可以檢查The Idiomatic Way to Merge Dictionaries in Python

+0

這不包含嵌套的'dict's。 – jdehesa

0

您可以使用dict.update方法,以及一個生成器表達式:

base_dict.update((k, v) for k, v in other_dict.items() if k in base_dict) 

說明

base_dict.update(other_dict)base_dict與那些在other_dict覆蓋值。 如果一個密鑰存在於other_dict但不在base_dict中,它將被添加到base_dict,這不是你想要的。 因此,您需要測試other_dict中的每個密鑰是否在base_dict之間。

dict.update可以採用迭代作爲第一個參數。如果後者包含2元組(k, v),則base_dict[k]將被設置爲v

摘要從help(dict.update)

更新(...)builtins.dict實例的方法

如果E存在和缺乏.keys()方法,則這樣的:對於K,V在E:D [k] = v

因此,將生成器表達式傳遞給它是很方便的。 如果你不熟悉生成器表達式中,括號內的東西是以下或多或少相當於:

l = [] 
for k, v in other.dict_items(): 
    if k in base_dict: 
     l.append((k, v)) 

然後l傳遞給update,像base_dict.update(l)

+0

同樣,這不包含嵌套的'dict's。 – jdehesa