您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Python:轻松访问深度嵌套的字典(获取和设置)

Python:轻松访问深度嵌套的字典(获取和设置)

一个规范的问题在于,Python无法告诉您__getitem__,在处my_obj.a.b.c.d,您是否下一步将继续沿着不存在的树进行操作,在这种情况下,它需要使用一种__getitem__方法返回一个对象,因此您不会被AttributeError抛出,或者如果您想要一个值,则需要返回None

我认为,在每种情况下,您都应该期望它抛出KeyError而不是返回None。原因是您无法分辨是否None表示“无钥匙”或“实际存储None在该位置的人”。对于此行为,您所需要做的就是takedotdictify,removemarker和替换__getitem__为:

def __getitem__(self, key):
    return self[key]

因为您真正想要的是dictwith__getattr____setattr__

可能有一种方法可以__getitem__完全删除并说一些类似的内容__getattr__ = dict.__getitem__,但是我认为这可能是过度优化的问题,如果您以后决定要__getitem__dotdictify最初那样创建树,那么这将是一个问题,在这种情况下,您会更改为:

def __getitem__(self, key):
    if key not in self:
        dict.__setitem__(self, key, dotdictify())
    return dict.__getitem__(self, key)

我不喜欢marker原来的生意dotdictify

第二个规范(overrideget()set())是,法线dictget()操作与您描述的不同,甚至不包含set(尽管其setdefault()操作与操作相反get())。人们期望get采用两个参数,如果找不到密钥,则第二个参数为认值。

如果要扩展__getitem____setitem__处理点键符号,则需要修改doctictify为:

class dotdictify(dict):
    def __init__(self, value=None):
        if value is None:
            pass
        elif @R_403_937@(value, dict):
            for key in value:
                self.__setitem__(key, value[key])
        else:
            raise TypeError, 'expected dict'

    def __setitem__(self, key, value):
        if '.' in key:
            myKey, restOfKey = key.split('.', 1)
            target = self.setdefault(myKey, dotdictify())
            if not @R_403_937@(target, dotdictify):
                raise KeyError, 'cannot set "%s" in "%s" (%s)' % (restOfKey, myKey, repr(target))
            target[restOfKey] = value
        else:
            if @R_403_937@(value, dict) and not @R_403_937@(value, dotdictify):
                value = dotdictify(value)
            dict.__setitem__(self, key, value)

    def __getitem__(self, key):
        if '.' not in key:
            return dict.__getitem__(self, key)
        myKey, restOfKey = key.split('.', 1)
        target = dict.__getitem__(self, myKey)
        if not @R_403_937@(target, dotdictify):
            raise KeyError, 'cannot get "%s" in "%s" (%s)' % (restOfKey, myKey, repr(target))
        return target[restOfKey]

    def __contains__(self, key):
        if '.' not in key:
            return dict.__contains__(self, key)
        myKey, restOfKey = key.split('.', 1)
        target = dict.__getitem__(self, myKey)
        if not @R_403_937@(target, dotdictify):
            return False
        return restOfKey in target

    def setdefault(self, key, default):
        if key not in self:
            self[key] = default
        return self[key]

    __setattr__ = __setitem__
    __getattr__ = __getitem__

测试代码

>>> life = dotdictify({'bigBang': {'stars': {'planets': {}}}})
>>> life.bigBang.stars.planets
{}
>>> life.bigBang.stars.planets.earth = { 'singleCellLife' : {} }
>>> life.bigBang.stars.planets
{'earth': {'singleCellLife': {}}}
>>> life['bigBang.stars.planets.mars.landers.vikings'] = 2
>>> life.bigBang.stars.planets.mars.landers.vikings
2
>>> 'landers.vikings' in life.bigBang.stars.planets.mars
True
>>> life.get('bigBang.stars.planets.mars.landers.spirit', True)
True
>>> life.setdefault('bigBang.stars.planets.mars.landers.opportunity', True)
True
>>> 'landers.opportunity' in life.bigBang.stars.planets.mars
True
>>> life.bigBang.stars.planets.mars
{'landers': {'opportunity': True, 'vikings': 2}}
python 2022/1/1 18:31:53 有221人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶