Python中的字典數據結構

字典又稱爲哈希表(hashmap)、映射(map),它是以key-value的方式進行存儲,經過key進行存儲、查找操做的效率很是高。在Python編碼中字典也是很是很是經常使用的一種數據結構。
今天就看下Python中有哪些實現字典的數據結構。 本文中提到的代碼都是Python3.7中執行的。html

字典的存儲其實很像一個數組。在字典中的key對象是必須實現__hash____eq__方法的。在字典在查找時會計算keyhash值,而後經過模運算快速的定位到「數組」的下標,若是這個下標只有一個元素,那麼就直接返回該value;若是有多個元素都存儲在同一個下標裏面,就再使用__eq__方法進行比較,相同者返回。python

0x00 dict

dict估計是最經常使用到的一種數據結構了,能夠存儲Python中的對象。shell

>>> d = {'one':1,'two':2,'three':33}
>>> d
{'one': 1, 'two': 2, 'three': 33}
# 在for循環中默認是遍歷keys
>>> keys = [k for k in d]
>>> keys
['one', 'two', 'three']
# 也能夠使用
>>> keys = [x for x in d.keys()]
>>> keys
['one', 'two', 'three']
# 遍歷values
>>> values = [v for v in d.values()]
>>> values
[1, 2, 33]
# 若是要遍歷key,value能夠使用dict.items()方法,它返回一個(k,v)元組
>>> kvs = [(k,v) for k,v in d.items()]
>>> kvs
[('one', 1), ('two', 2), ('three', 33)]
複製代碼

如今Python3.6以上版本中的dict是很是強大的,遍歷時會保持元素插入Python中的順序json

>>> d = {'z':2,'a':'111','b':0.99}
>>> d
# 輸出時保持元素的插入順序
{'z': 2, 'a': '111', 'b': 0.99}
複製代碼

當獲取一個不存在的key,將會拋出KeyError數組

>>> d['k']
Traceback (most recent call last):
  File "<pyshell#172>", line 1, in <module>
    d['k']
KeyError: 'k'
複製代碼

若是不想拋出異常錯誤信息,那麼能夠使用get方法,並能夠指定當key不存在時,返回默認值。這個方法在實際的編碼中也是很是實用的。bash

# 當`key`不存在時,指定返回默認值
>>> d.get('k',314)
314
複製代碼

例如在WEB應用解析服務器端返回的json數據時,經常會把json數據解析成一個字典,若是服務端的某個字段缺失了,而客戶端使用下標的方法來進行訪問元素時,就會出現KeyError。要讓本身的程序更加健壯,那麼就能夠使用get方法。服務器

0x01 collections.OrderedDict

OrderedDict能保持元素的存儲順序,若是你使用的Python版本還比較低,或者爲了兼容舊版本的Python,並且你的需求中對元素的插入順序比較重要的話,那麼能夠使用這個類。數據結構

>>> import collections
>>> d = collections.OrderedDict(one=1, two=2, three=3)
>>> d
OrderedDict([('one', 1), ('two', 2), ('three', 3)])
>>> d['one']
1
>>> d['four']
# 一樣地,若是key不存在,也會拋出KeyError
KeyError: 'four'
>>> d.get('four',4)
4
>>> d.keys()
odict_keys(['one', 'two', 'three'])
>>> d.items()
odict_items([('one', 1), ('two', 2), ('three', 3)])
複製代碼

0x02 collections.defaultdict

當獲取一個不存在的key時提供默認值。defaultdict在構造的時候就須要提供一個默認類型,用於當key不存在時,構造默認的類型。app

例如我構造一個用戶未讀數列表,經過用戶ID來獲取用戶的未讀數,當在字典中沒有找到用戶ID時,默認的未讀數就是0。函數

>>> from collections import defaultdict
# 使用defaultdict構造一個用戶未讀數字典,並傳入int類型做爲默認值的類型
>>> user_unreads = defaultdict(int)
# 給ID爲123,121,120的用戶添加的未讀數
>>> user_unreads[123]=2
>>> user_unreads['121']=3
>>> user_unreads['120']=9
>>> user_unreads
defaultdict(<class 'int'>, {123: 2, '121': 3, '120': 9})
>>> user_unreads['121']
3
# 當獲取一個不存在的字典中的用戶ID時,使用默認值
>>> user_unreads['129']
0
複製代碼

defaultdict構造函數仍是能夠使用其它類型,例如list

>>> dd = defaultdict(list)
>>> dd
defaultdict(<class 'list'>, {})
>>> dd['user_list']
[]
>>> dd['user_list'].append('jack')
>>> dd['user_list'].append('tom')
>>> dd['user_list'].append('rose')
>>> dd
defaultdict(<class 'list'>, {'user_list': ['jack', 'tom', 'rose']})
複製代碼

0x03 collections.ChainMap

ChainMap類能夠方便地處理多個字典的操做。例如將兩個字典拼接到一塊兒

>>> from collections import ChainMap
>>> d1 = {'one': 1, 'two': 2}
>>> d2 = {'three': 3, 'four': 4}
>>> chain = ChainMap(d1, d2)
>>> chain
ChainMap({'one': 1, 'two': 2}, {'three': 3, 'four': 4})
>>> chain['two']
2
>>> chain['five']
# 獲取一個不存在的key,會拋出KeyError
KeyError: 'five'
複製代碼

0x04 types.MappingProxyType

types.MappingProxyType類能夠構造一個只讀的字典,這個對數據的封裝和控制很是有用。例如當咱們不但願有人修改咱們的數據時,能夠考慮使用這個類。

該類內部實際上是對內置dict的封裝,對外提供一個只讀接口,當被封裝的類修改了,這MappingProxyType的對象也會發生變化。

>>> from types import MappingProxyType
# 構造一個普通的字典
>>> writable = {'one': 1, 'two': 2}
# 經過MappingProxyType構造函數封裝字典
>>> read_only = MappingProxyType(writable)
>>> read_only['one']
1
>>> read_only['one'] = 23
# 若是對mappingproxy對象進行修改,則會拋出異常
TypeError: 'mappingproxy' object does not support item assignment
# 能夠對原始對象進行修改,這個修改也會馬上響應到mappingproxy對象中去
>>> writable['one'] = 42
>>> read_only
mappingproxy({'one': 42, 'two': 2})
複製代碼

0x05 總結一下

通常來講,內置dict對象已經足以知足咱們大部分的需求開發,這也是咱們使用字典這種數據類型的首選的數據結構。若是你有其它一些特殊需求,能夠看看這裏列出的OrderedDictdefaultdictChainMapMappingProxyType

0x06 學習資料

相關文章
相關標籤/搜索