Python添加/更新任何深度的dict元素

时间:2015-11-12 02:17:33

标签: python dictionary

有这样的字典

my_pets = {
    'Rudolf': {
        'animal': 'cat', 
        'legs': 4
    }
}

达到以下相同的清洁方式是什么?

my_pets['Rudolf']['legs']['front-right']['injured'] = True
my_pets['Rudolf']['legs']['front-left']['injured'] = False

它应该更新为

my_pets = {
    'Rudolf': {
        'animal': 'cat', 
        'legs': {
            'front-right': {'injured':True},
            'front-left': {'injured':False}
        }
    }
}

5 个答案:

答案 0 :(得分:4)

你可以创建一个“无限”的默认指令,如下所示:

from collections import defaultdict

def infinidict():
    return defaultdict(infinidict)

然后写:

>>> my_pets = infinidict()
>>> my_pets['Rudolf']['animal'] = 'cat'
>>> my_pets['Rudolf']['weight'] = 3
>>> my_pets['Rudolf']['legs']['front-right']['injured'] = True
>>> my_pets
defaultdict(<function __main__.infinidict>,
            {'Rudolf': defaultdict(<function __main__.infinidict>,
                         {'animal': 'cat',
                          'legs': defaultdict(<function __main__.infinidict>,
                                      {'front-right': defaultdict(<function __main__.infinidict>,
                                                   {'injured': True})}),
                          'weight': 3})})

输出看起来很混乱,但my_pets只能在需要dict的地方使用。

答案 1 :(得分:4)

下面是一个字典子类,它对于缺少任意深度的键很宽松:

d = freedict()
d['one']['two']['three'] = 1
d.one.two.three = 2

这可以像这样使用(对键的属性访问是个人偏好):

{{1}}

答案 2 :(得分:1)

这是一个非常有趣且非常实际的情况。 有许多实现都解决了某些问题,并错过了一些边缘场景。

可以在这些标题中找到可能的解决方案和不同的答案。

  

What is the best way to implement nested dictionaries?

     

What's the best way to initialize a dict of dicts in Python?

     

Set nested dict value and create intermediate keys

此外,还有许多关于此要求的博客和博客&#39; autovivification&#39;包括维基百科的存在。

  

http://blog.yjl.im/2013/08/autovivification-in-python.html

     

https://news.ycombinator.com/item?id=3881171

     

https://gist.github.com/hrldcpr/2012250

     

https://en.wikipedia.org/wiki/Autovivification

     

http://blogs.fluidinfo.com/terry/2012/05/26/autovivification-in-python-nested-defaultdicts-with-a-specific-final-type/

虽然上述实现方便一旦边缘情况仍然存在问题。在撰写本文时,没有任何实现已经很好地处理了是否存在原始坐位和阻塞嵌套。

以下是在StackOverflow中回答此问题和相关问题的3种主要方式。

  • 编写一个辅助方法,它接受字典,值和嵌套键列表 适用于普通的dict对象,但缺少通常的方括号语法,

  • 使用Defaultdict并编写自定义类,从根本上说这是有效的,因为默认dict为缺少的键提供{} 很棒的语法,但仅适用于使用自定义类创建的对象。

  • 使用元组存储和检索(https://stackoverflow.com/a/651930/968442) 最糟糕的想法,甚至不应该声称是解决方案,这就是为什么

    mydict = {}
    mydict['foo', 'bar', 'baz'] = 1
    print mydict['foo', 'bar', 'baz']

    工作正常,但当您访问mydict['foo', 'bar']时,期望为{'baz':1},而不是KeyError 这基本上摧毁了可迭代的概念。嵌套结构

在这三种方法中,我的选择是选项1.通过编写一个小辅助方法,边缘情况可以用实际方法解决,这是我的实现。

def sattr(d, *attrs):
    # Adds "val" to dict in the hierarchy mentioned via *attrs
    for attr in attrs[:-2]:
        # If such key is not found or the value is primitive supply an empty dict
        if d.get(attr) is None or isinstance(d.get(attr), dict):
            d[attr] = {}
        d = d[attr]
    d[attrs[-2]] = attrs[-1]

现在

my_pets = {'Rudolf': {'animal': 'cat', 'legs': 4}}
sattr(my_pets, 'Rudolf', 'legs', 'front-right', 'injured', True)
sattr(my_pets, 'Rudolf', 'legs', 'front-left', 'injured', False)

将产生

{'Rudolf': {'legs': 4, 'animal': 'cat'}}
{'Rudolf': {'legs': {'front-right': {'injured': True}}, 'animal': 'cat'}}
{'Rudolf': {'legs': {'front-left': {'injured': False}, 'front-right': {'injured': True}}, 'animal': 'cat'}}

答案 3 :(得分:0)

尝试使用try

try:

    # checks whether 'front-right' exists. If exists assigns value. Else raises   exception
    my_pets['Rudolf']['legs']['front-right']= {'injured':True}}

except:

    # On raising exception add 'front-right' to 'legs'
    my_pets['Rudolf']['legs'] = {'front-right': {'injured':True}}

这应该有效

答案 4 :(得分:0)

这将允许您根据列表的任意深度向dict添加一个键 按键。

  def add_multi_key(subscripts, _dict={}, val=None):
        """Add an arbitrary length key to a dict.

        Example:

            out = add_multi_key(['a','b','c'], {}, 1 )

            out -> {'a': {'b': {'c':1}}}

        Arguments:
            subscripts, list of keys to add
            _dict, dict to update. Default is {}
            val, any legal value to a key. Default is None.

        Returns:
            _dict - dict with added key.
        """
        if not subscripts:
            return _dict
        subscripts = [s.strip() for s in subscripts]
        for sub in subscripts[:-1]:
            if '_x' not in locals():
                if sub not in _dict:
                    _dict[sub] = {}
                _x = _dict.get(sub)
            else:
                if sub not in _x:
                    _x[sub] = {}
                _x = _x.get(sub)
        _x[subscripts[-1]] = val
        return _dict