主题内容不是很好描述,就通过下面的例子来说明下我们经常遇到KeyError报错.
In [15]: data = {"blog":"xiaorui.cc"}
In [16]: data['blog']
Out[16]: 'xiaorui.cc'
In [17]: data['at']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-17-9652e590cd98> in <module>()
----> 1 data['at']
KeyError: 'at'
In [18]: data['at']['sign'] = 'github.com'
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-18-8909e479937d> in <module>()
----> 1 data['at']['sign'] = 'github.com'
KeyError: 'at'
文章写的不是很严谨,欢迎来喷,另外该文后续有更新的,请到原文地址查看更新。
对, 就是这个使用python字典时常常遇到的KeyError问题… 当你要实现一个比较复杂的字典,含有各种嵌套层,比如 xiaorui[‘a’][‘b’][‘c’] = “ok”, 要往c写值前要确认a b是否有,要不然会报错的. 除了写入数据之外,读取字典同样会遇到这类似的问题,get只能获取最近一层key,不能获取嵌套的字典key。
那么怎么解决? 难度我们要一层层的判断字典?
我们可以设计一个继承了dict的类,实现的方法也很是简单,只要使用__getitem__魔法函数就可以模拟友好的字典。
#blog: xiaorui.cc
class MagicDict(dict):
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
a = MagicDict()
a[1][2][3] = 4
a[2][2]['test'] = 6
print 'end'
print a[1]
for i in a:
print i
python2.7的collections有个defaultdict类,他的实现跟上面类似,多加了一些废话方法而已.
#blog: xiaorui.cc
In [2]: from collections import defaultdict
In [3]: a = defaultdict(dict)
In [4]: a['hell']['good']= 'xiaorui.cc'
In [5]: a
Out[5]: defaultdict(<type 'dict'>, {'hell': {'good': 'xiaorui.cc'}})
#########################################
__missing__
In [15]: d={}
In [16]: d.setdefault('rui', {}).setdefault('woca', {})['nima']=3
老规矩 ! 下面我们来瞅瞅collections defaultdict的源码.
class defaultdict(dict):
def __init__(self, default_factory=None, *args, **kwargs):
if (default_factory is not None and
not hasattr(default_factory, '__call__')):
raise TypeError(b_('First argument must be callable'))
dict.__init__(self, *args, **kwargs)
self.default_factory = default_factory
#当我们获取key时触发的函数.
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
return self.__missing__(key)
#当我无法找到嵌套的key时会触发, 需要注意的是这里的__missing__跟method call的那个不一样.
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
self[key] = value = self.default_factory()
return value
def __reduce__(self):
if self.default_factory is None:
args = tuple()
else:
args = self.default_factory,
return type(self), args, None, None, self.iteritems()
def copy(self):
return self.__copy__()
def __copy__(self):
return type(self)(self.default_factory, self)
def __deepcopy__(self, memo):
import copy
return type(self)(self.default_factory,
copy.deepcopy(self.items()))
def __repr__(self):
if isinstance(self.default_factory, types.MethodType) \
and self.default_factory.im_self is not None \
and issubclass(self.default_factory.im_class, defaultdict):
defrepr = '<bound method sub._factory of defaultdict(...'
else:
defrepr = repr(self.default_factory)
return 'defaultdict(%s, %s)' % (defrepr, dict.__repr__(self))
__all__ = ('defaultdict',)
对于数据格式很是混乱, 很是蛋疼的时候还是挺适合用这种友好的字典模式,如果对于数据格式的需求比较认真,那还是用普通的字典吧. 就比如为什么有很多人喜欢nosql里的mongodb,因为他的bson格式很是随意,但是这样会代码业务bug的产生… 当然还是看人,看业务…
END.
