当前位置: 首页 > 面试题库 >

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

唐高朗
2023-03-14
问题内容

我正在构建一些Python代码来读取和操作深层嵌套的dict(最终是为了与JSON服务进行交互,但是,将其用于其他用途将非常有用)我正在寻找一种方法,可以轻松地在内部深层读取/设置/更新值dict,不需要很多代码。

@另请参阅Python:通过属性以及索引访问来递归访问dict?-Curt
Hagenlocher的“ DotDictify”解决方案非常雄辩。我也喜欢Ben
Alman在http://benalman.com/projects/jquery-getobject-
plugin/中为JavaScript呈现的内容。 以某种方式将两者结合起来将是很棒的。

在Curt Hagenlocher和Ben Alman的示例的基础上,在Python中具有以下功能将是很棒的:

>>> my_obj = DotDictify()
>>> my_obj.a.b.c = {'d':1, 'e':2}
>>> print my_obj
{'a': {'b': {'c': {'d': 1, 'e': 2}}}}
>>> print my_obj.a.b.c.d
1
>>> print my_obj.a.b.c.x
None
>>> print my_obj.a.b.c.d.x
None
>>> print my_obj.a.b.c.d.x.y.z
None

知道这是否可行,如果可行,如何修改DotDictify解决方案?

或者,可以使get方法接受点符号(并添加了互补的set方法),但是对象符号确定更干净。

>>> my_obj = DotDictify()
>>> my_obj.set('a.b.c', {'d':1, 'e':2})
>>> print my_obj
{'a': {'b': {'c': {'d': 1, 'e': 2}}}}
>>> print my_obj.get('a.b.c.d')
1
>>> print my_obj.get('a.b.c.x')
None
>>> print my_obj.get('a.b.c.d.x')
None
>>> print my_obj.get('a.b.c.d.x.y.z')
None

这种类型的交互对于处理深度嵌套的字典非常有用。是否有人知道可以尝试的其他策略(或示例代码片段/库)?


问题答案:

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

我认为,在每种情况下,您都应该期望它抛出KeyError而不是返回None。原因是您无法分辨是否None表示“无钥匙”或“实际存储None在该位置的人”。对于此行为,您所需要做的就是take
dotdictify,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 isinstance(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 isinstance(target, dotdictify):
                raise KeyError, 'cannot set "%s" in "%s" (%s)' % (restOfKey, myKey, repr(target))
            target[restOfKey] = value
        else:
            if isinstance(value, dict) and not isinstance(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 isinstance(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 isinstance(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}}


 类似资料:
  • 问题内容: 我的应用程序中有一个非常复杂的数据结构,需要对其进行操作。我试图跟踪玩家在他们的花园中有多少种错误。有十种错误,每种错误都有十种模式,每种模式都有十种颜色。所以可能有1000个独特的错误,我想追踪玩家每种类型的错误数量。嵌套的字典如下所示: 我没有使用此语法的任何错误或投诉。 当我想增加播放器的错误收集时,请执行以下操作: 我收到此错误: 字符串不能转换为’DictionaryInde

  • 问题内容: 我是python的新手,需要帮助解决问题: 我有像这样的字典 除了做其他事情,我们还有其他方法可以获取三个价值吗? ? 问题答案: 您可以在每个字典上使用get()。确保已为每个访问添加了“无”检查。

  • 我有一个JSON API响应,如下所示: 我正在使用Python并尝试访问响应中的第一个“下载”值。所以我需要从sales\u list(目录中的列表)开始 我见过关于在列表中的字典或嵌套字典中访问值的问题。但是我对如何在字典中的列表和列表中的字典之间/之间导航有点困惑。任何帮助都将不胜感激。

  • 问题内容: 我正在用Go编写一个websocket客户端。我正在从服务器接收以下JSON: 我正在尝试访问该参数,但无法掌握如何深入了解接口类型: 显然是错误的,因为这种表示法是不正确的: 我只是找不到一种方法来挖掘地图以获取深层嵌套的键和值。 一旦可以克服动态值,我便想声明这些消息。我将如何编写类型结构来表示这种复杂的数据结构? 问题答案: 您解码成的部分将与该字段的类型匹配。因此,在这种情况下

  • 问题内容: 我有一本包含字典的字典,其中可能还包含字典,例如 目前,我正在打开包装以获取ID 001的“开单至”,“交易参考” a1,如下所示: 我忍不住觉得这有点笨拙,尤其是最后两行-我觉得以下内容应该可以工作: 有没有一种更简单的方法可以向下钻取嵌套字典而不必解压缩临时变量? 问题答案: 实际有效。是表示的表达式,因此您可以在其中进行查找。对于实际程序,我更喜欢使用面向对象的方法来嵌套字典。对

  • 问题内容: 我已经从网站下载了json数据,我想从嵌套的json中选择特定的key:values。我将json转换为python字典。然后,我使用字典理解来选择嵌套的key:values,但是嵌套太多了,我相信有比单独扩展每个字典更好的方法。我在我的方法中看到了冗余。您能建议一个更好的方法吗? 我的方法: 从datetime导入datetime,timedelta 问题答案: 我建议您使用,具有完