python自建 属性访问 (内部一致) 的 字典 data type

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

原文地址:https://www.cnblogs.com/willowj/p/8187927.html