字典:
字典在
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’]