映射类型(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}