Python基礎:映射(字典)

1、概述

映射類型(Mapping Types)是一種關聯式的容器類型,它存儲了對象與對象之間的映射關係。html

字典(dict)是Python中惟一的映射類型,它是存儲了一個個 鍵值對(由 映射到 )的關聯容器。其中,(key)必須是可哈希的Python對象,而 (value)能夠是任何Python對象。在功能上,Python中的字典相似於C++中的map。python

Python中最強大、最靈活的數據類型當屬 列表字典,如下是對這兩種數據類型的簡單比較:數組

比較點 列表 字典
表示方法 [],[1, 2] {},{'a': 1, 'b': 2}
訪問元素的方式 索引
有序性 有序 無序
可變性 可變 可變
可操做性 操做豐富 操做豐富
表徵的數據結構 數組、堆棧、隊列等 哈希表等

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}

3、字典特性

一、有序與無序

從概念上講,字典提供了這樣一種抽象:容器中的元素之間徹底獨立(因而也沒有前後順序),「鍵」是訪問元素的惟一方式。在這種 抽象層面 上,字典是 無序 的。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知足如下兩個條件:

  • hash(keyA) == hash(keyB)
  • cmp(keyA, keyB) == 0

若是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'}

4、字典視圖

從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

5、應用

一、模擬switch-case語句

如下是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}
相關文章
相關標籤/搜索