Python 字典
字典
字典当中的元素是通过键来存取的,而不是通过偏移存取。
主要属性:
- 通过键而不是偏移量来读取
- 任意对象的无序集合
- 可变长、异构、任意嵌套
- 属于可变映射类型 通过给索引赋值,字典可以在原处修改,但不支持用于字符串和列表中的序列操作。字典是唯一内置的映射类型。
- 对象引用表(散列表) 本质上, 字典是作为散列表来实现的。和列表一样,字典存储的是对象引用(不是拷贝)。
在Python3.0中,我们必须将keys放到一个llist调用中——Python3.0中的keys返回一个迭代器,而不是一个物理的列表。list调用迫使它一次生成所有的值,一边我们可以将其打印出来。在Python2.6中,keys构建并返回一个真正的列表,因此,list调用不需要显示结果。
>>> D = {1:'zhang', 2:'wang', 3:'li', 4:'zhao'} >>> list(D.keys()) [1, 2, 3, 4]
向字典中已存在的索引赋值会改变与索引相关联的值。然而,与列表不同的是,每当对新字典键进行赋值,就会在字典内生成一个新的元素。
>>> D = {'spam': 2, 'ham': 1, 'eggs': 3} >>> list(D.values()) [2, 1, 3] >>> list(D.items()) [('spam', 2), ('ham', 1), ('eggs', 3)]
这类列表在需要逐项遍历字典项的循环中是很有用的。读取不存在的键往往都会出错,然而键不存在时通过get方法能够返回默认值(None或者用户定义的默认值)。
>>> D.get('spam') 2 >>> D.get('toast', 88) 88
字典的update方法有点类似于合并,但是,它和从左往右的顺序无关。它把字典的键和值合并到另一个字典中,盲目地覆盖相同键的值:
>>> D2 = {'toast': 4, 'muffin': 5} >>> D.update(D2) >>> D {'spam': 2, 'ham': 1, 'eggs': 3, 'toast': 4, 'muffin': 5}
字典的pop方法能够从字典中删除一个键并返回它的值。
>>> D {'spam': 2, 'ham': 1, 'eggs': 3, 'toast': 4, 'muffin': 5} >>> D.pop('muffin') 5 >>> D.pop('toast') 4 >>> D {'spam': 2, 'ham': 1, 'eggs': 3}
Python也能够让你遍历字典的键列表,而并不用在多数for循环中调用keys方法。就任何字典D而言,写成for key in D:和写成完整的key in D.keys():效果是一样的。
字典用法注意事项
- 序列运算无效
- 对新索引赋值会添加项
- 键不一定总是字符串
字典用于稀疏数据结构
避免missing--key错误的三种方法:
>>> Matrix = {} >>> Matrix[(2,3,4)] = 88 >>> Matrix[(7,8,9)] = 99 >>> if (2,3,6) in Matrix: print(Matrix[(2,3,6)]) else: print(0) 0 >>> try: print(Matrix[(2,3,6)]) except KeyError: print(0) 0 >>> Matrix.get((2,3,4), 0) 88 >>> Matrix.get((2,3,6), 0) 0
创建字典的其他方法
>>> {'name': 'mel', 'age': 45} {'name': 'mel', 'age': 45}
>>> D = {} >>> D['name'] = 'mel' >>> D['age'] = 45
>>> dict(name = 'mel', age = 45) {'name': 'mel', 'age': 45}
>>> dict([('name', 'mel'), ('age', 45)]) {'name': 'mel', 'age': 45}
这四种形式都会建立相同的两键字典,但它们在不同的条件下有用:
- 如果你可以事先拼出整个字典,那么第一种是很方便的。
- 如果你需要一次动态地建立字典的一个字段,第二种比较合适。
- 第三种关键字形式所需的代码量比常量少,但是键必须都是字符串才行。
- 如果你需要在程序运行时把键和值逐步建成序列,那么最后一种形式比较有用。
如果所有键的值都相同,你也可以用这个特殊的形式对字典进行初始化——简单地传入一个键列表,以及所有见的初始值(默认值为空):
>>> dict.fromkeys(['a', 'b'], 0) {'a': 0, 'b': 0}
Python3.0中的字典变化
- 支持新的字典解析式表达式,这是列表和集合解析的“近亲”。
- 对于D.key 、D.values 和D.items方法,返回可迭代的视图,而不是列表。
- 由于前面一点,需要新的编码方式通过排序键来遍历。
- 不在直接支持相对大小比较——取而代之的是手动比较。
- 不再有D.has_key方法——相反,使用in成员关系测试。
字典解析
字典解析只在Python3.0中可用(Python2.0中不可用)。动态初始化一个字点的标准方式都是:将其键和值对应起来并把结果传递给dict调用。zip函数是在一个单个调用中从键和值的列表来构建一个字典的方式之一。如果不能在代码中预计键和值的集合,总是可以将他们构建为列表然后再对应起来:
>>> list(zip(['a', 'b', 'c'],[1, 2, 3])) [('a', 1), ('b', 2), ('c', 3)] >>> D = dict(zip(['a', 'b', 'c'],[1, 2, 3])) >>> D {'a': 1, 'b': 2, 'c': 3}
用字典解析表达式来实现同样的效果:
>>> D = {k:v for (k, v) in zip(['a', 'b', 'c'], [1, 2, 3])} >>> D {'a': 1, 'b': 2, 'c': 3}
我们可以使用它们把单独的一串值映射到字典,并且键和值一样,也可以用表达式来计算:
>>> D = {x: x ** 2 for x in [1, 2, 3, 4]} >>> D {1: 1, 2: 4, 3: 9, 4: 16} >>> D = {c: c * 4 for c in 'SPAM'} >>> D {'S': 'SSSS', 'P': 'PPPP', 'A': 'AAAA', 'M': 'MMMM'} >>> D = {c.lower(): c + '!' for c in ['SPAM', 'EGGS', 'HAM']} >>> D {'spam': 'SPAM!', 'eggs': 'EGGS!', 'ham': 'HAM!'}
从键列表初始化
>>> D = dict.fromkeys(['a', 'b', 'c'], 0) >>> D {'a': 0, 'b': 0, 'c': 0} >>> D = {k:0 for k in['a', 'b', 'c']} >>> D {'a': 0, 'b': 0, 'c': 0} >>> D = dict.fromkeys('spam') >>> D {'s': None, 'p': None, 'a': None, 'm': None} >>> D = {k:None for k in 'spam'} >>> D {'s': None, 'p': None, 'a': None, 'm': None}
在Python3.0中,字典的keys、values和items都返回视图对象。视图对象是可迭代的,这就意味着对象每次产生一个结果项。另外,字典视图还保持了字典成分的最初的顺序,反映字典未来的修改,并且能够支持集合操作。另一方面,它们不是列表,并且不支持像索引和列表sort方法这样的操作,打印的时候它们也不显示自己的项。
如果想要应用列表操作或者显示它们的值,我们必须通过内置函数list来运行这3个方法的结果:
>>> D = dict(a = 1, b = 2, c=3) >>> D {'a': 1, 'b': 2, 'c': 3} >>> k = D.keys() >>> list(k) ['a', 'b', 'c'] >>> list(D.items()) [('a', 1), ('b', 2), ('c', 3)]
与Python2.x不同,Python3.0中的子第三视图并非创建后不能改变——它们可以动态地反映在视图对象创建之后对字典做出的修改:
>>> D = dict(a = 1, b = 2, c=3) >>> D {'a': 1, 'b': 2, 'c': 3} >>> k = D.keys() >>> list(k) ['a', 'b', 'c'] >>> v = D.values() >>> list(v) [1, 2, 3] >>> del D['b'] >>> D {'a': 1, 'c': 3} >>> list(k) ['a', 'c'] >>> list(v) [1, 3]
keys方法所返回的Python3.0的视图对象类似于集合,并且支持交集和并集等常见的集合操作;values视图不是这样的,因为他们不是唯一的;但items结果是的,如果(key, value)对是唯一的并且可散列的话。
>>> D {'a': 1, 'c': 3, 'b': 2} >>> D.keys() & {'b'} {'b'} >>> D.keys() & {'b': 1} {'b'} >>> D.keys() | {'b', 'c', 'd'} {'c', 'd', 'a', 'b'}
如果字典项视图是可散列的话,它们是类似于集合的——也就是说,如果他们只包括不可变的对象的话:
>>> D {'a': 1, 'c': 3, 'b': 2} >>> list(D.items()) [('a', 1), ('c', 3), ('b', 2)] >>> D.items() | D.keys() {('b', 2), 'b', 'c', ('c', 3), ('a', 1), 'a'} >>> D.items() | D {'c', ('c', 3), ('a', 1), ('b', 2), 'a', 'b'} >>> dict(D.items() | {('c', 3), ('d',4)}) {'c': 3, 'a': 1, 'b': 2, 'd': 4}
排序字典键
>>> D {'a': 1, 'c': 3, 'b': 2} >>> ks = D.keys() >>> ks = list(ks) >>> ks.sort() >>> ks ['a', 'b', 'c'] >>> for k in ks :print(k, D[k]) a 1 b 2 c 3 >>> D {'a': 1, 'c': 3, 'b': 2} >>> ks = D.keys() >>> for k in sorted(ks): print(k, D[k]) a 1 b 2 c 3 >>> D {'a': 1, 'c': 3, 'b': 2} >>> for k in sorted(D): print(k, D[k]) a 1 b 2 c 3
字典大小比较不再有效
Python2.6中可以直接用<、>等比较字典的相对大小,但在Python3.0中这不再有效。然而,可以通过手动第比较排序后的键列表来模拟:
sorted(D1.items()) < sorted(D2.items())
has_key 方法已死:in永生
>>> D {'a': 1, 'c': 3, 'b': 2} >>> 'c' in D True >>> 'x' in D False >>> print(D.get('c')) 3
>>> if D.get('c') != None: print('present', D['c']) present 3 >>> if D.get('c'): print('present', D['c']) present 3