任務
你有一個巨大的字典,字典中的一些鍵屬于一個特定的集合,而你想創建一個包含這個鍵集合及其對應值的新字典。
解決方案
如果你不想改動原字典:
def sub_dict(somedict,somekeys,default = None):return dict([(k, somedict.get(k,default)) for k in somekeys ])
如果你從原字典中刪除那些符合條件的條目:
def sub_dict_remove(somedict,somekeys,default = None):return dict([ (k, somedict.pop(k,default)) for k in somekeys ])
下面是兩個函數的使用和效果:
>>>d = {'a':5,'b':6,'c':7}
>>>print sub_dict(d,'ab'),d
{'a':5,'b':6}{'a':5,'b':6,'c': 7}
>>> print sub_dict_remove(d,'ab'),d
{'a':5,'b':6}{'c':7}
討論
在 Python 中,我在很多地方都用到了字典——數據庫的行、主鍵和復合鍵,用于模板解析的變量名字空間等。我常常需要基于另外一個已有的大字典創建一個新字典,此字典的鍵是大字典的鍵的一個子集。在大多數情況下,原字典應該保持不變;但有時,我也需要在完成了抽取之后刪除在原字典中的子集。本節的解決方案對兩種可能性都給出了答案。區別僅僅在于,如果需要原字典保持原樣不變,使用get方法,如果需要刪除子集,則使用 pop 方法。
如果 somekeys 中的某元素k并不是 somedict的鍵,解決方案提供的函數會將k作為結果的鍵,并對應一個默認值(可以作為一個可選的參數傳遞給這兩個函數,默認情況下是 None)。所以,最終結果也不一定是somedict 的子集。不過我卻發現這種行為方式對我的應用非常有幫助。
當你認為 somekeys中的所有的元素都應當是 somedict 的鍵時,也許會希望在鍵“缺失的時候獲得一個異常,它可以提示和警告你程序中的bug。記住,Tim Peters 在 The Zeno/Python 中說過“錯誤不應該被靜靜地略過,除非有意為之”(在 Python 的交互式解釋器的提示符下敲入 import this 并回車,你將看到精煉的 Python 設計原則)。所以,如果從你的應用的角度看,鍵不匹配是一個錯誤,那么會希望馬上得到一個異常來提醒你錯誤的發生。如果這的確是你所希望的,可以對解決方案中的函數略作修改:
def sub_dict_strict(somedict,somekeys):return dict([ (k,somedict[k]) for k in somekeys ])
def sub_dict_remove_strict(somedict,somekeys):return dict([ (k,somedict.pop(k)) for k in somekeys ])
這些更加嚴格的變體版本甚至比原版本更簡單——這充分說明了Python 本來就喜歡在意外發生時拋出異常。
或者,你希望在鍵不匹配時直接將其忽略。這也只需要一點點修改:
def sub_dict_select(somedict,somekeys):return dict([ (k,somedict[k[) for k in somekeys if k in somedict])
def sub_dict_remove_select(somedict,somekeys):return dict([ (k,somedict,pop(k)) for k in somekeys if k in somedict))
列表推導中的if子句做完了我們期望的事,即在應用k之前先做鑒別工作。
在 Python 2.4中可以用生成器表達式來替代列表推導,用它作為本節中的函數的參數。我們只需略微修改 dict 的調用,將 dict([…])改成 dict(…)(移除臨近圓括號的方括號),就能享受進一步的簡化和速度的提升。不過這些修改不適用 Python2.3,因為它只支持列表推導而不支持生成器表達式。