映射類型(Mapping Types)是一種關聯式的容器類型,它存儲了對象與對象之間的映射關係。html
字典(dict)是Python中惟一的映射類型,它是存儲了一個個 鍵值對(由 鍵 映射到 值)的關聯容器。其中,鍵(key)必須是可哈希的Python對象,而 值(value)能夠是任何Python對象。在功能上,Python中的字典相似於C++中的map。python
Python中最強大、最靈活的數據類型當屬 列表 和 字典,如下是對這兩種數據類型的簡單比較:數組
比較點 | 列表 | 字典 |
---|---|---|
表示方法 | [],[1, 2] | {},{'a': 1, 'b': 2} |
訪問元素的方式 | 索引 | 鍵 |
有序性 | 有序 | 無序 |
可變性 | 可變 | 可變 |
可操做性 | 操做豐富 | 操做豐富 |
表徵的數據結構 | 數組、堆棧、隊列等 | 哈希表等 |
字典支持的主要操做以下:markdown
操做 | 說明 |
---|---|
class dict(other) | 建立字典(other能夠是字典、(key, value)對的迭代器或關鍵字參數) |
dict.fromkeys(seq[, value]) | 建立字典:用序列seq中的元素做爲鍵,值全爲value(未指定,則默認爲None) |
len(d) | 返回字典d的長度(即d中元素的個數) |
d[key] | 若是鍵key在字典d中,則返回其中key對應的值;不然拋出KeyError異常 |
d[key] = value | 設置d[key]的值爲value(存在則修改,不存在則添加) |
del d[key] | 若是鍵key在字典d中,則從字典d中刪除d[key];不然拋出KeyError異常 |
key in d | 若是key在字典d中,返回True;不然,返回False |
key not in d | 若是key在字典d中,返回False;不然,返回True |
iter(d) | 同iterkeys() |
d.clear() | 刪除字典d中的全部元素 |
d.copy() | 返回字典d的淺拷貝 |
d.get(key[, default]) | 若是key在字典d中,則返回d[key];不然返回default(未指定,則默認爲None) |
d.has_key(key) | 同key in d(推薦使用key in d) |
d.items() | 返回包含字典d中的(key, value)對的列表 |
d.iteritems() | 迭代版的items():返回迭代器 |
d.iterkeys() | 迭代版的keys():返回迭代器 |
d.itervalues() | 迭代版的values():返回迭代器 |
d.keys() | 返回包含字典d中的鍵的列表 |
d.pop(key[, default]) | 若是key在字典d中,則返回並刪除d[key];不然返回default(未指定,則拋出KeyError異常) |
d.popitem() | 返回並刪除字典d中的任意一個元素(若是d爲空,則拋出KeyError異常) |
d.setdefault(key[, default]) | 若是key在字典d中,則返回d[key];不然執行d[key] = default,並返回default(未指定,則默認爲None) |
d.update([other]) | 將other中的(key, value)對添加到字典d中(other能夠是字典、(key, value)對的迭代器或關鍵字參數) |
d.values() | 返回包含字典d中的值的列表 |
d.viewitems() | 返回字典d的元素視圖 |
d.viewkeys() | 返回字典d的鍵視圖 |
d.viewvalues() | 返回字典d的值視圖 |
以上操做的示例以下:數據結構
>>> a = {'one': 1, 'two': 2, 'three': 3} >>> b = dict(one=1, two=2, three=3) >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3])) >>> d = dict({'three': 3, 'one': 1, 'two': 2}) >>> a == b == c == d True >>> d = dict.fromkeys(['a', 'b', 'c']) >>> d {'a': None, 'c': None, 'b': None} >>> d = dict.fromkeys(['a', 'b', 'c'], 6) >>> d {'a': 6, 'c': 6, 'b': 6} >>> len(d) 3 >>> d.clear() >>> d {} >>> d = a.copy() >>> d {'one': 1, 'three': 3, 'two': 2} >>> d['three'] 3 >>> d['four'] = 4 >>> d {'four': 4, 'one': 1, 'three': 3, 'two': 2} >>> del d['one'] >>> d {'four': 4, 'three': 3, 'two': 2} >>> 'four' in d, 'four' not in d (True, False) >>> d.has_key('four') True >>> d.get('one'), d.get('one', 10) (None, 10) >>> for k in d: ... print k, ... four three two >>> for k in iter(d): ... print k, ... four three two >>> for k in d.keys(): ... print k, ... four three two >>> for k in d.iterkeys(): ... print k, ... four three two >>> for k in d.viewkeys(): ... print k, ... four three two >>> for v in d.values(): ... print v, ... 4 3 2 >>> for v in d.itervalues(): ... print v, ... 4 3 2 >>> for v in d.viewvalues(): ... print v, ... 4 3 2 >>> for i in d.items(): ... print i, ... ('four', 4) ('three', 3) ('two', 2) >>> for i in d.iteritems(): ... print i, ... ('four', 4) ('three', 3) ('two', 2) >>> for i in d.viewitems(): ... print i, ... ('four', 4) ('three', 3) ('two', 2) >>> d.setdefault('two') 2 >>> d {'four': 4, 'three': 3, 'two': 2} >>> d.setdefault('one', 1) 1 >>> d {'four': 4, 'one': 1, 'three': 3, 'two': 2} >>> d.update(five=1) >>> d {'four': 4, 'one': 1, 'five': 1, 'three': 3, 'two': 2} >>> d.update({'six': 6}) >>> d {'four': 4, 'five': 1, 'two': 2, 'six': 6, 'three': 3, 'one': 1} >>> d.pop('four') 4 >>> d {'five': 1, 'two': 2, 'six': 6, 'three': 3, 'one': 1} >>> d.popitem() ('five', 1) >>> d {'two': 2, 'six': 6, 'three': 3, 'one': 1}
從概念上講,字典提供了這樣一種抽象:容器中的元素之間徹底獨立(因而也沒有前後順序),「鍵」是訪問元素的惟一方式。在這種 抽象層面 上,字典是 無序 的。app
從實現上講,字典實際上是由 哈希表 實現的。而哈希表的基本思想是:經過 哈希函數(hash function)將「鍵」轉換爲「索引」,再使用「索引」去訪問 連續列表(如C中的數組)中的元素。由此可知,在哈希表中:一方面,元素本質上是存儲在一個連續列表中的,所以是 有序 的;另外一方面,用戶沒法肯定元素在連續列表中的實際位置(只能使用「鍵」去訪問元素,而「鍵」與「索引」的映射關係是由哈希函數在內部指定的),所以又是 無序 的。函數
所以在 實現層面 上,字典同時具有了 無序 和 有序 的特色:ui
上圖對應的示例以下:3d
# 無序 >>> d = {} >>> d['a'] = 1 >>> d {'a': 1} >>> d['b'] = 2 >>> d {'a': 1, 'b': 2} >>> d['c'] = 3 >>> d {'a': 1, 'c': 3, 'b': 2} # 有序 >>> for k in d: # 鍵的順序固定 ... print k, ... a c b >>> for v in d.values(): # 值的順序固定 ... print v, ... 1 3 2 >>> for i in d.items(): # 元素的順序固定 ... print i, ... ('a', 1) ('c', 3) ('b', 2)
字典的鍵具備如下特性:code
1)可哈希的(hashable)
只有 可哈希的 對象才能做爲字典的鍵,一個可哈希的對象必須知足如下兩個條件:
__hash__()
方法)__eq__()
或__cmp__()
方法)Python中可哈希的對象有:
__hash__()
和__cmp__()
來修改默認行爲)2)哈希等價鍵
假設有字典d的兩個鍵:keyA和keyB,咱們稱keyA和keyB是 哈希等價鍵(本身杜撰的名詞),若是keyA和keyB知足如下兩個條件:
若是keyA和keyB是哈希等價鍵,那麼它們將被視爲徹底相同的兩個鍵,因而d[keyA]和d[keyB]會指向同一個字典元素。
例如,1和1.0就知足上述兩個條件,所以是哈希等價鍵:
>>> hash(1), hash(1.0) (1, 1) >>> cmp(1, 1.0) 0 >>> d = {} >>> d[1] = 'int 1' >>> d {1: 'int 1'} >>> d[1.0] = 'float 1' >>> d {1: 'float 1'}
對於用戶自定義的類實例,默認狀況下(即沒有實現__hash__()
和__cmp__()
時),hash(...)和cmp(...)的結果與 id() 有關(參考 hashable 和 __cmp__())。默認狀況下,一個自定義類的任意兩個實例都不是哈希等價鍵:
>>> class A: pass ... >>> a1 = A() >>> a2 = A() >>> hash(a1), hash(a2) (-1064359592, -1064359600) >>> cmp(a1, a2) 1 >>> d = {} >>> d[a1] = 'a1' >>> d {<__main__.A instance at 0x8f2958c>: 'a1'} >>> d[a2] = 'a2' >>> d {<__main__.A instance at 0x8f2958c>: 'a1', <__main__.A instance at 0x8f2950c>: 'a2'}
若是想要讓同一個類的任意兩個實例都是哈希等價鍵,則能夠參考如下示例:
>>> class A: ... def __hash__(self): ... return hash(A) ... def __cmp__(self, other): ... return cmp(self.__hash__(), other.__hash__()) ... >>> a1 = A() >>> a2 = A() >>> hash(a1), hash(a2) (-1064346499, -1064346499) >>> cmp(a1, a2) 0 >>> d = {} >>> d[a1] = 'a1' >>> d {<__main__.A instance at 0x8f64a4c>: 'a1'} >>> d[a2] = 'a2' >>> d {<__main__.A instance at 0x8f64a4c>: 'a2'}
相似地,若是想要讓一個類的任意一個實例與整數1成爲哈希等價鍵,則能夠按照如下方式實現:
>>> class A: ... def __hash__(self): ... return 1 ... def __cmp__(self, other): ... return cmp(self.__hash__(), other.__hash__()) ... >>> a = A() >>> hash(1), hash(a) (1, 1) >>> cmp(1, a) 0 >>> d = {} >>> d[1] = 'int 1' >>> d {1: 'int 1'} >>> d[a] = 'instance a' >>> d {1: 'instance a'}
從2.7版本開始,Python中引入了字典視圖(Dictionary views)。字典視圖 是字典的 動態視圖:它們會與字典保持同步,實時反應出字典的變化。字典視圖共有3種:鍵視圖(Keys views)、值視圖(Values views)和 元素視圖(Items views),它們分別由dict.viewkeys()、dict.viewvalues()和dict.viewitems()三個函數返回。
全部的字典視圖都支持如下操做:
操做 | 說明 |
---|---|
len(dictview) | 返回字典的長度 |
iter(dictview) | 返回(鍵、值、元素)迭代器 |
x in dictview | 判斷x是否爲(鍵、值、元素)的成員 |
此外,由於字典的鍵是 惟一 且 可哈希的,因此 鍵視圖 還支持 相似集合(set-like)的操做。若是字典的值是 可哈希的,那麼 元素視圖 也支持這些操做:
操做 | 說明 |
---|---|
dictview & other | 求交集 |
dictview | other | 求並集 |
dictview - other | 求差集 |
dictview ^ other | 求對稱差集 |
關於字典視圖的示例,請參考 Dictionary view objects。
如下是C中一個使用switch-case語句的示例:
int select(char c) { int num = -1; switch (c) { case 'a': num = 1; break; case 'b': num = 2; break; case 'c': num = 3; break; default: num = 0; break; } return num; }
Python中沒有提供switch-case語句,但使用字典能夠輕鬆實現相似上面的功能:
d = {'a': 1, 'b': 2, 'c': 3} # 普通版本 def select1(c): num = -1 if c not in d: num = 0 else: num = d[c] return num # 驚呆版本 def select2(c): return d.get(c, 0)
使用元組做爲字典的鍵,能夠構建相似稀疏矩陣的數據結構:
>>> matrix = {} >>> matrix[(2, 3, 4)] = 88 >>> matrix[(7, 8, 9)] = 99 >>> >>> matrix {(2, 3, 4): 88, (7, 8, 9): 99} >>> >>> x, y, z = 2, 3, 4 >>> matrix[(x, y, z)] 88
實際上,Python自己就在內部大量使用了字典,一個典型的應用就是符號表:
>>> locals() # 局部符號表 {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None} >>> globals() # 全局符號表 {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}