字典物件的 Pythonic 用法(上)

發表於2017-06-09

字典物件在Python中作為最常用的資料結構之一,和數字、字串、列表、元組並列為5大基本資料結構,字典中的元素通過鍵來存取,而非像列表一樣通過偏移存取。筆者總結了字典的一些常用Pyhonic用法,這是字典的Pythonic用法的上篇

0. 使用 in/not in 檢查 key 是否存在於字典

判斷某個 key 是否存在於字典中時,一般初學者想到的方法是,先以列表的形式把字典所有鍵返回,再判斷該key是否存在於鍵列表中:

更具Pythonic的用法是使用in關鍵字來判斷 key 是否 存在於字典中:

1. 使用 setdefault() 初始化字典鍵值

使用字典的時候經常會遇到這樣一種應用場景:動態更新字典,像如下程式碼,如果 key 不在 dictionary 中那麼就新增它並把它對應的值初始為空列表 [] ,然後把元素 append 到空列表中:

儘管這段程式碼沒有任何邏輯錯誤,但是我們可以使用setdefault來實現更Pyhonic的寫法:

字典呼叫 setdefault 方法時,首先檢查 key 是否存在,如果存在該方法什麼也不做,如果不存在 setdefault 就會建立該 key,並把第二個引數[]作為 key 對應的值。

2. 使用 defaultdict() 初始化字典

初始化一個字典時,如果初始情況下希望所有 key 對應的值都是某個預設的初始值,比如有一批使用者的信用積分都初始為100,現在想給 a 使用者增加10分

同樣這段程式碼也沒任何問題,換成更pyhtonic的寫法是:

defaultdict 是位於 collections 模組下,它是 dict 類的子類,語法結構是:

第一個引數default_factory是一個工廠方法,每次初始化某個鍵的時候將會被呼叫,value就是default_factory返回的值,剩下的引數和dict()函式接收的引數一樣

3. 使用 iteritems() 迭代大資料

迭代大資料字典時,如果是使用 items() 方法,那麼在迭代之前,迭代器迭代前需要把資料完整地載入到記憶體,這種方式不僅處理非常慢而且浪費記憶體,下面程式碼約佔1.6G記憶體(為什麼是1.6G?可以參考:http://stackoverflow.com/questions/4279358/pythons-underlying-hash-data-structure-for-dictionaries

而使用 iteritem() 方法替換 items() ,最終實現的效果一樣,但是消耗的記憶體降低50%,為什麼差距那麼大呢?因為 items() 返回的是一個 list,list 在迭代的時候會預先把所有的元素載入到記憶體,而 iteritem() 返回的一個迭代器(iterators),迭代器在迭代的時候,迭代元素逐個的生成。

4. 高效合併字典

普通方法

合併多個字典的時候可以用一行程式碼實現:

這種寫法看起來很Pythonic,但仔細分析的話,它的執行效率並不高,items()方法在python2.7中返回的是列表物件,兩個列表相加得到一個新的列表,這樣記憶體中存在3個列表物件,如果兩個列表的大小都是1G,那麼執行這段程式碼需要佔用4G的空間來建立這個字典。此外這段程式碼在Python3中會報錯,因為python3中items()返回的是dict_items物件,而不是列表。

在python3中,你需要明確地強制轉換成list物件:

Pythonic方法

在Python3.5中提供了一種全新的Pythonic方法:

不過考慮到大部分系統還是基於Python2,所以一種更相容的pythonic方法是:

當然,你可以把它封裝成一個函式:

其他方法

還有其他方式來合併字典,但是效能不一定是最優的,比如: python2.7可以支援字典推導式

python2.6及以下版本使用

效能對比

直接使用python3.5中的{**x, **y}是最快的,使用update次之,用字典推導式相對來說是最慢的。

相關文章