字典(dictionary)
我们都曾经利用过语言辞书来查找不认识的单词的界说。语言辞书针对给定的单词(好比 python)提供一组尺度的信息。这种系统将界说和其他信息与实际的单词关联(映射)起来。利用单词作为键定位器来寻找感乐趣的信息。这种观念延伸到 Python 编程语言中,就成了非凡的容器范例,称为 字典(dictionary)。
字典(dictionary) 数据范例在很多语言中都存在。它有时候称为关联 数组(因为数据与一个键值相关联),可能作为散列表。可是在 Python 中,字典(dictionary) 是一个很好的工具,因此纵然是编程新手也很容易在本身的措施中利用它。凭据正式的说法,Python 中的 字典(dictionary) 是一种异构的、易变的映射容器数据范例。
建设字典
本系列中前面的文章先容了 Python 编程语言中的一些容器数据范例,包罗 tuple、string 和 list(拜见 参考资料)。这些容器的相似之处是它们都是基于序列的。这意味着要按照元素在序列中的位置会见这些荟萃中的元素。所以,给定一个名为 a 的序列,就可以利用数字索引(好比 a[0] )或片断(好比 a[1:5])来会见元素。Python 中的 字典(dictionary) 容器范例与这三种容器范例的差异之处在于,它是一个无序的荟萃。不是凭据索引号,而是利用键值来会见荟萃中的元素。这意味着结构字典(dictionary)容器比 tuple、string 或 list 要巨大一些,因为必需同时提供键和相应的值,如清单 1 所示。
清单 1. 在 Python 中建设字典,第 1 部门
>>> d = {0: 'zero', 1: 'one', 2 : 'two', 3 : 'three', 4 : 'four', 5: 'five'} >>> d {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'} >>> len(d) >>> type(d) # Base object is the dict class <type 'dict'> >>> d = {} # Create an empty dictionary >>> len(d) >>> d = {1 : 'one'} # Create a single item dictionary >>> d {1: 'one'} >>> len(d) >>> d = {'one' : 1} # The key value can be non-numeric >>> d {'one': 1} >>> d = {'one': [0, 1,2 , 3, 4, 5, 6, 7, 8, 9]} >>> d {'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
如这个例子所示,在 Python 中建设字典(dictionary)要利用花括号和以冒号脱离的键-值组合。假如没有提供键-值组合,那么就会建设一个空的 dictionary。利用一个键-值组合,就会建设具有一个元素的 dictionary,以此类推,直至您需要的任何局限。与任何容器范例一样,可以利用内置的 len 要领查明荟萃中元素的数量。
前面的示例还演示了关于字典(dictionary)容器的另一个重要问题。键并不限制为整数;它可以是任何不易变的数据范例,包罗 integer、float、tuple 或 string。因为 list 是易变的,所以它不能作为字典(dictionary)中的键。可是字典(dictionary)中的值可以是任何数据范例的。
最后,这个示例说明白 Python 中字典(dictionary)的底层数据范例是 dict 工具。要进一步相识如何利用 Python 中的 字典(dictionary),可以利用内置的辅佐表明器来相识 dict 类,如清单 2 所示。
清单 2. 得到关于字典(dictionary)的辅佐
>>> help(dict)on class dict in module __builtin__: dict(object) | dict() -> new empty dictionary. | dict(mapping) -> new dictionary initialized from a mapping object's | (key, value) pairs. | dict(seq) -> new dictionary initialized as if via: | d = {} | for k, v in seq: | d[k] = v | dict(**kwargs) -> new dictionary initialized with the name=value pairs | in the keyword argument list. For example: dict(one=1, two=2) | | Methods defined here: | | __cmp__(...) | x.__cmp__(y) <==> cmp(x,y) | | __contains__(...) | x.__contains__(y) <==> y in x | | __delitem__(...) | x.__delitem__(y) <==> del x[y] ...
#p#分页标题#e#
关于 dict 类的辅佐指出,可以利用结构函数直接建设字典(dictionary),而不利用花括号。既然与其他容器数据范例对比,在建设字典(dictionary)时必需提供更多的数据,那么这些建设要领较量巨大也就不敷为奇了。可是,在实践中利用字典(dictionary)并不难,如清单 3 所示。
清单 3. 在 Python 中建设字典(dictionary),第 2 部门
>>> l = [0, 1,2 , 3, 4, 5, 6, 7, 8, 9] >>> d = dict(l)(most recent call last): File "<stdin>", line 1, in ?: can't convert dictionary update sequence element #0 to a sequence >>> l = [(0, 'zero'), (1, 'one'), (2, 'two'), (3, 'three')] >>> d = dict(l) >>> d {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> l = [[0, 'zero'], [1, 'one'], [2, 'two'], [3, 'three']] >>> d {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> d = dict(l) >>> d {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> d = dict(zero=0, one=1, two=2, three=3) >>> d {'zero': 0, 'three': 3, 'two': 2, 'one': 1} >>> d = dict(0=zero, 1=one, 2=two, 3=three): keyword can't be an expression
可以看到,建设字典(dictionary)需要键值和数据值。第一次从 list 建设字典(dictionary)的实验失败了,这是因为没有匹配的键-数据值对。第二个和第三个示例演示了如何正确地建设 字典(dictionary):在第一种环境下,利用一个 list,个中的每个元素都是一个 tuple;在第二种环境下,也利用一个 list,可是个中的每个元素是另一个 list。在这两种环境下,内层容器都用于得到键到数据值的映射。
直接建设 dict 容器的另一个要领是直接提供键到数据值的映射。这种技能答允显式地界说键和与其对应的值。这个要领其实用处不大,因为可以利用花括号完成沟通的任务。别的,如前面的例子所示,在回收这种方法时对付键不能利用数字,不然会导致抛出一个异常。
会见和修改字典(dictionary)
建设了 dictionary 之后,需要会见个中包括的数据。会见方法与会见任何 Python 容器数据范例中的数据相似,如清单 4 所示。
清单 4. 会见 dictionary 中的元素
>>> d = dict(zero=0, one=1, two=2, three=3) >>> d {'zero': 0, 'three': 3, 'two': 2, 'one': 1} >>> d['zero'] >>> d['three'] >>> d = {0: 'zero', 1: 'one', 2 : 'two', 3 : 'three', 4 : 'four', 5: 'five'} >>> d[0] 'zero' >>> d[4] 'four' >>> d[6](most recent call last): File "<stdin>", line 1, in ?: 6 >>> d[:-1](most recent call last): File "<stdin>", line 1, in ?: unhashable type
可以看到,从字典(dictionary)中获取数据值的进程险些与从任何容器范例中获取数据完全一样。在容器名后头的方括号中放上键值。虽然,字典(dictionary)可以具有非数字的键值,假如您以前没有利用过这种数据范例,那么适应这一点需要些时间。因为在字典(dictionary)中序次是不重要的(dictionary 中数据的序次是任意的),所以可以对其他容器数据范例利用的片断成果,对付 字典(dictionary)是不行用的。试图利用片断可能试图从不存在的键会见数据就会抛出异常,指出相关的错误。
#p#分页标题#e#
Python 中的字典(dictionary)容器也是易变的数据范例,这意味着在建设它之后可以修改它。如清单 5 所示,可以添加新的键到数据值的映射,可以修改现有的映射,还可以删除映射。
清单 5. 修改字典(dictionary)
>>> d = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> d[0] 'zero' >>> d[0] = 'Zero' >>> d {0: 'Zero', 1: 'one', 2: 'two', 3: 'three'} >>> d[4] = 'four' >>> d[5] = 'five' >>> d {0: 'Zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'} >>> del d[0] >>> d {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'} >>> d[0] = 'zero' >>> d {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
清单 5 演示了几个重点。首先,修改数据值是很简朴的:将新的值分派给适当的键。其次,添加新的键到数据值的映射也很简朴:将相关数据分派给新的键值。Python 自动举办所有处理惩罚。不需要挪用 append 这样的非凡要领。对付 dictionary 容器,序次是不重要的,所以这应该好领略,因为不是在字典(dictionary)后头附加映射,而是将它添加到容器中。最后,删除映射的步伐是利用 del 操纵符以及应该从容器中删除的键。
在清单 5 中有一个环境看起来有点儿怪,键值是凭据数字序次显示的,并且这个序次与插入映射的序次沟通。不要误解 —— 环境不老是这样的。Python 字典(dictionary)中映射的序次是任意的,对付差异的 Python 安装大概会有变革,甚至多次利用同一 Python 表明器运行沟通代码也会有变革。假如在一个字典(dictionary)中利用差异范例的键和数据值,那么就很容易看出这一点,如清单 6 所示。
清单 6. 异构的容器
>>> d = {0: 'zero', 'one': 1} >>> d {0: 'zero', 'one': 1} >>> d[0] 'zero' >>> type(d[0]) <type 'str'> >>> d['one'] >>> type(d['one']) <type 'int'> >>> d['two'] = [0, 1, 2] >>> d {0: 'zero', 'two': [0, 1, 2], 'one': 1} >>> d[3] = (0, 1, 2, 3) >>> d {0: 'zero', 3: (0, 1, 2, 3), 'two': [0, 1, 2], 'one': 1} >>> d[3] = 'a tuple' >>> d {0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1}
如这个例子所示,可以在一个字典(dictionary)中利用差异数据范例的键和数据值。还可以通过修改字典(dictionary)添加新的范例。最后,发生的 dictionary 的序次并不与插入数据的序次匹配。本质上,字典(dictionary)中元素的序次是由 Python 字典(dictionary)数据范例的实际实现节制的。新的 Python 表明器很容易改变这一序次,所以必然不要依赖于元素在字典(dictionary)中的特定序次。
用字典(dictionary)举办编程
作为正式的 Python 数据范例,字典(dictionary)支持其他较简朴数据范例所支持的大大都操纵。这些操纵包罗一般的干系操纵符,好比 <、> 和 ==,如清单 7 所示。
清单 7. 一般干系操纵符
>>> d1 = {0: 'zero'} >>> d2 = {'zero':0} >>> d1 < d2 >>> d2 = d1 >>> d1 < d2 >>> d1 == d2 >>> id(d1) >>> id(d2) >>> d2 = d1.copy() >>> d1 == d2 >>> id(d1) >>> id(d2)
前面的示例建设两个字典(dictionary)并利用它们测试 < 干系操纵符。尽量很少以这种方法较量两个字典(dictionary);可是假如需要,可以这样做。
#p#分页标题#e#
然后,这个示例将赋值给变量 d1 的字典(dictionary)赋值给另一个变量 d2。留意,内置的 id() 要领对付 d1 和 d2 返回沟通的标识符值,这说明这不是复制操纵。要想复制字典(dictionary) ,可以利用 copy() 要领。从这个示例中的最后几行可以看出,副本与本来的字典(dictionary)完全沟通,可是容纳这字典(dictionary)的变量具有差异的标识符。
在 Python 措施中利用字典(dictionary)时,很大概但愿查抄字典(dictionary)中是否包括特定的键或值。如清单 8 所示,这些查抄很容易执行。
清单 8. 条件测试和字典(dictionary)
>>> d = {0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1} >>> d.keys() [0, 3, 'two', 'one'] >>> if 0 in d.keys(): ... print 'True' ... >>> if 'one' in d: ... print 'True' ... >>> if 'four' in d: ... print 'Dictionary contains four' ... elif 'two' in d: ... print 'Dictionary contains two' ... contains two
测试字典(dictionary)中键或数据值的成员干系是很简朴的。dictionary 容器数据范例提供几个内置要领,包罗 keys() 要领和 values() 要领(这里没有演示)。这些要领返回一个列表,个中别离包括举办挪用的字典(dictionary)中的键或数据值。
因此,要判定某个值是否是字典(dictionary)中的键,应该利用 in 操纵符查抄这个值是否在挪用 keys() 要领所返回的键值列表中。可以利用相似的操纵查抄某个值是否在挪用 values() 要领所返回的数据值列表中。可是,可以利用字典(dictionary)名作为简写暗示法。这是有意义的,因为一般但愿知道某个数据值(而不是键值)是否在字典(dictionary)中。
在 “Discover Python, Part 6” 中,您看到了利用 for 轮回遍历容器中的元素是何等容易。同样的技能也合用于 Python 字典(dictionary),如清单 9 所示。
清单 9. 迭代和字典(dictionary)
>>> d = {0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1} >>> for k in d.iterkeys(): ... print d[k] ... tuple [0, 1, 2] >>> for v in d.itervalues(): ... print v ... tuple [0, 1, 2] >>> for k, v in d.iteritems(): ... print 'd[',k,'] = ',v ... [ 0 ] = zero[ 3 ] = a tuple[ two ] = [0, 1, 2][ one ] = 1
这个示例演示了遍历字典(dictionary)的三种方法:利用从 iterkeys()、itervalues() 或 iteritems() 要领返回的 Python 迭代器。(顺便说一下,可以通过在字典(dictionary)上直接挪用适当要领,好比 d.iterkeys(),从而查抄这些要领是否返回一个迭代器而不是容器数据范例。)iterkeys() 要领答允遍历字典(dictionary)的键,而 itervalues() 要领答允遍历字典(dictionary)包括的数据值。另一方面,iteritems() 要领答允同时遍历键到数据值的映射。
字典(dictionary):另一种强大的 Python 容器
本文接头了 Python 字典(dictionary)数据范例。字典(dictionary)是一种异构的、易变的容器,依赖键到数据值的映射(而不是特定的数字序次)来会见容器中的元素。会见、添加和删除字典(dictionary)中的元素都很简朴,并且字典(dictionary)很容易用于复合语句,好比 if 语句或 for 轮回。可以在字典(dictionary)中存储所有差异范例的数据,可以凭据名称或其他复合键值(好比 tuple)会见这些数据,所以 Python 字典(dictionary)使开拓人员可以或许编写简捷而又强大的编程语句。