字典:
字典在python也是一种经常使用的数据结构。在数据的存储很方便。首先来看下字典中对于键值的处理。在字典index中,只有a:1这一个键值对。如果去取b的键值,则会抛出异常报错。提示找不到键值
index={'a':1} print index['b']
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
Traceback (most recent call last):
File "E:/py_prj/fluent_python/chapter3.py", line 9, in <module>
get_item()
File "E:/py_prj/fluent_python/chapter3.py", line 5, in get_item
print index['b']
KeyError: 'b'
在这种键值找不到的情况下会直接抛出异常,导致程序中断。这是可以用get的方法来设置当找不到对应的键值时候的默认值。
index={'a':1} print index.get('b',[])
此是虽然也找不到键值,但是不会抛出异常,而是直接返回一个空的列表。这比刚才方便多了
再把需求提升一下,当找不到键值的时候,不光是返回一个指定值,还需要对这个列表对这个缺失的键值进行更新。需要如何操作呢。代码更新如下。
index={'a':1} missing=index.get('b',]) #第一步没找到b,则返回一个空列表给missing missing.append(2) #missing列表添加一个新元素 index['b']=missing #在字典中更新b的值 print index
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
{'a': 1, 'b': [2]}
上面的例子总共用了三步来完成字典缺失字段的更新。有没有一种更简便的方法呢。Dict.setdefault可以用一行代码来解决。代码如下。
index={'a':1} index.setdefault('b',[]).append(2) print index
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
{'a': 1, 'b': [2]}
在代码中,查找,更新用一行代码完成,相比前面的例子,对于字典只进行了一次查询。
需求再升级一下,有没有一种字典类型,当找不到对应的键值的时候自动更新数值呢。这里就要用到defaultdict。
index=collections.defaultdict(list) #这里用defaultdict生成一个字典,并且用list构造方法作为default_factory来创建一个defaultdict
index['a'].append(1) print index
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
defaultdict(<type 'list'>, {'a': [1]})
如果不设置这个default_factory.会是什么结果。
index=collections.defaultdict()
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
Traceback (most recent call last):
File "E:/py_prj/fluent_python/chapter3.py", line 16, in <module>
default_try()
File "E:/py_prj/fluent_python/chapter3.py", line 10, in default_try
index['a'].append(1)
KeyError: 'a'
这里会抛出异常。证明当找不到键值的时候,会调用defalut_factory创建一个默认值。在Python所有的数据都是类。对于字典也是如此,在进行index[a]的时候其实是调用的__getitem__。那么在找不到键值的时候,其实是调用的__missing__这个方法。
我们首先来看下代码中对于__missing__的定义,注释中写道__missing__是被__getitem__所调用的。当default_factory为空的时候,则抛出异常。否则则用default_facotry来更新。
def __missing__(self, key): # real signature unknown; restored from __doc__ """ __missing__(key) # Called by __getitem__ for missing key; pseudo-code: if self.default_factory is None: raise KeyError((key,)) self[key] = value = self.default_factory() return value """
我们首先来看下书中的代码:
class StrkeyDict0(dict): def __missing__(self,key): if isinstance(key,str): raise KeyError(key) return self[str(key)] def get(self,key,default=None): try: return self[key] except KeyError: return default def __contains__(self, key): return key in self.keys() or str(key) in self.keys()
d=StrkeyDict0([('2','two'),('4','four')]) print d[1]
运行结果如下:抛出了异常。
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
Traceback (most recent call last):
File "E:/py_prj/fluent_python/chapter3.py", line 30, in <module>
print d[1]
File "E:/py_prj/fluent_python/chapter3.py", line 17, in __missing__
return self[str(key)]
File "E:/py_prj/fluent_python/chapter3.py", line 16, in __missing__
raise KeyError(key)
KeyError: '1'
断点来看下这个程序的运行:
第一步:key是整数1,判断不是字符串,则执行return self[str(key)]。首先将key转换成字符串,然后在字典中取这个值
第二步:Key 变成了字符,此时判断属于字符,抛出 KeyError
我们将__missing__改写下。当找不到键值的时候。直接进行赋值。
def __missing__(self,key): if isinstance(key,str): self[key]='three' return self[str(key)
那么运行结果就是
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
three
我们再回到最开始的代码,看下get方法的调用
d=StrkeyDict0([('2','two'),('4','four')]) print d.get(3,[])
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
[]
单步调试下:
第一步:
Key值为3,找不到对应的键值,下一步跳到__missing__方法处理
第二步__missing__中首先转换成字符查找一次
第三步,字符3还是找不到,则跑出KeyError的异常
第四步,接收到异常,于是返回defalut值,也就是调用的时候d.get(3,[])
的空列表。
继续更新下代码:就和之前用dict来设置缺省的键值一
样。
d=StrkeyDict0([('2','two'),('4','four')]) ret=d.get(3,[]) ret.append('three') d[3]=ret print d[3]
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
['three']
此时print d[3]就是[‘three’]