python自建 属性访问 (内部一致) 的 字典 date type
taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Felidae']['Felis']['cat']
#>>>>
taxonomy.Animalia.Chordata.Mammalia.Carnivora.Felidae.Felis.cat
继承dict,重写__getattr__
、__settattr__
就行了:
class adict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, val):
self[attr] = val
d = adict(a={'b':9})
print d.a
# {u'b': 9}
d.k = {'p':5}
但是,再往里层属性访问:print d.a.b
,raiseAttributeError: 'dict' object has no attribute 'b'
; d.k = {'p':5}
这样新进入的也不支持。
它只是个壳子,里层其实没有变;不能一层层用下去,用的时候你得时刻考虑 class type
,
或者不停地显示转换类型 d = adict(a=adict({'b':9}))
这也太不 pythonic.
d = adict({'j': [0]}, a=9, b={'p': 5})
d.b.p
#Out[436]: 5
so,要 能属性访问方法一致,那得需要 把所有 自身下层的 dict 转 成 adict。
这样:
还需要重写 __setitem__
update
code:
class adict(dict):
'''dict support attr access'''
def __init__(self, ele_=None, **kwargs):
self.update(ele_, **kwargs)
def __setitem__(self, item, value):
# ! key method !; 'dict[k] = v' will use 'self.__setitem__(k,v)'
# not to recur , use super
if not isinstance(value, type(self)) and isinstance(value, dict):
value = type(self).conv(value)
super(adict, self).__setitem__(item, value)
def update(self, ele=None, **kwargs):
# rewrite
if ele:
if hasattr(ele, "keys"):
for k in ele:
self[k] = ele[k]
else:
for (k, v) in ele:
self[k] = v
for k in kwargs:
self[k] = kwargs[k]
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, val):
self[attr] = val
@classmethod
def conv(cls, dic):
if not isinstance(dic, dict):
return dic
new_dic = cls.__new__(cls) # not trigger __init__
for k, v in dic.iteritems():
# __setitem__ use this, need super
super(cls, new_dic).__setitem__(k, cls.conv(v))
return new_dic
if __name__ == '__main__':
print('>> any dict in will be converted to adict<<
')
d = adict({'j': [0]}, a=9, b={'p': 5}) # creat a adict
print(d, '
', type(d), type(d.b)) # subdict is also adict
d.z = {'g': 6} # setitem
print(type(d.z), 'd.z.g:', d.z.g)
d.update({'kk': {'ko': 76}}) # update to adict
print(type(d.kk), 'd.kk.ko:', d.kk.ko, )
#----##->----------------------------------------
#----same as dict, shadow copy first level self-type container
print('-.'*30)
a = {1: 9, 'a': {u'p': 9}, 'b': [u'as']}
b = adict(a)
print('b is adict(b):', b is adict(b)) # False, same as dict
# a is dict(a)
# Out[263]: False
print('-'*30)
dic = dict(a)
print([a[k] is dic[k] for k in a.keys()])
adic = adict(b)
print([b[k] is adic[k] for k in b.keys()])
这样只要是adict type,标识符的key, 内部都能通过属性访问了。
插句话:python 的 dict 为什么不支持 属性访问?
字典的key支持int ,而,属性名必须是标识符;dict支持了int作为key,自然就不能再支持属性访问(如果key 为int,你还得转换为 [key] 访问,这么基础的操作都不具有一致性了)
另外,属性名,不能作为key这样变量来随意改变;不够动态,而python可是动态语言。
作为基础的容器类data tpye,不支持最基本的int,也不支持动态访问,要么方法不一致,自然是不合适的。
也可以继承collections里的UserDict。UserDict中data属性是dict,其他方法都模仿了 dict