流程python学习笔记:第三章(1)

来源:互联网 发布:中科院空间中心 知乎 编辑:程序博客网 时间:2024/06/07 08:49
字典:
字典在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,则返回一个空列表给missingmissing.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]=retprint d[3]
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter3.py
['three']
此时print d[3]就是[‘three’]