【问题标题】:Convenient way to handle deeply nested dictionary in Python在 Python 中处理深度嵌套字典的便捷方法
【发布时间】:2018-10-05 06:28:26
【问题描述】:

我在 python 中有一个深度嵌套的字典,占用了很多空间。有没有办法缩写像这样的东西

master_dictionary['sub_categories'][sub_cat_name]['attributes'][attribute_name]['special_type']['nested_children'][child_cat_name][color] = blue

以这个为例

nested_child_info[color] = blue

仍然让它编辑字典吗?我希望这是有道理的。

【问题讨论】:

  • 这是设置一件事的最快方法。如果您有更多数据要设置,您可以获取最小的公分母并从那里开始工作。

标签: python dictionary nested shorthand


【解决方案1】:
nested_child_info = master_dictionary['sub_categories'][sub_cat_name]['attributes'][attribute_name]['special_type']['nested_children'][child_cat_name]
nested_child_info[color] = blue

nested_child_info 是一个引用,因此更改其内容将更改master_dictionary 的内容。

【讨论】:

    【解决方案2】:

    你能做这样的事情吗?

    thing = {1: {2: {3: {4: {'hello': 'world'}}}}}
    a = thing[1]
    b = a[2]
    c = b[3]
    d = c[4]
    print(d) # {'hello': 'world'}
    

    【讨论】:

      【解决方案3】:

      由于字典是可变的,这实际上会完全按照您的预期发生:

      >>> test = {'outer': 'thing', 'inner': {'thing': 'im the inner thing'}}
      >>> inner_thing = test['inner']
      >>> inner_thing
      {'thing': 'im the inner thing'}
      >>> inner_thing['thing'] = 'im something new'
      >>> inner_thing
      {'thing': 'im something new'}
      >>> test
      {'outer': 'thing', 'inner': {'thing': 'im something new'}}
      

      这是因为可变对象在 python 中是通过引用传递的,而不是作为副本传递的(关于这方面的优秀文章很多,因此不再详述)。

      但是,值得注意的是,您实际上可能不想更改原始 dict,因为它可能会对使用此变量的其他代码产生不良影响(这取决于您的代码库)。在这种情况下,我通常会复制需要变异的数据以避免副作用:

      >>> from copy import deepcopy
      >>> test = {'outer': 'thing', 'inner': {'thing': 'im the inner thing'}}
      >>> new_test = deepcopy(test)
      >>> inner_thing = test['inner']
      >>> inner_thing['thing'] = 'im something new'
      >>> test
      {'outer': 'thing', 'inner': {'thing': 'im something new'}}
      >>> new_test
      {'outer': 'thing', 'inner': {'thing': 'im the inner thing'}}
      

      【讨论】:

        【解决方案4】:

        是的,你可以。

        >>> dict1 = {'foo':{'bar':{'baz':0}}}
        >>> dict2 = dict1['foo']['bar']
        >>> dict2['baz'] = 1
        >>> dict1
        {'foo': {'bar': {'baz': 1}}} # dict1 has been modified
        

        【讨论】:

          【解决方案5】:

          如果你有一些“固定”键,你总是可以创建一个函数:

          考虑这个例子:

          d = dict(a=dict(sub_categories=dict(b=1)))
          
          def changevalue(value, lvl1, lvl2):
              d[lvl1]['sub_categories'][lvl2] = value
          
          changevalue(2,'a','b')
          
          print(d)
          
          #{'a': {'sub_categories': {'b': 2}}}
          

          在你的情况下,你想退出:

          [sub_cat_name], [attribute_name], [child_cat_name], [color] ...也许

          【讨论】:

            【解决方案6】:

            类似于@fferri。您将始终必须在 long 列表中指定项目。使用reducegetitem 获取对最终字典的引用

            from functools import reduce
            from operator import getitem
            
            d = {1:{2:{3:{4:5}}}}
            
            foo = 2
            items = [1,foo,3]
            result = d
            info = reduce(getitem, items, d)
            
            
            >>> info[4]
            5
            >>> d
            {1: {2: {3: {4: 5}}}}
            >>> info[4] = 99
            >>> d
            {1: {2: {3: {4: 99}}}}
            

            我也在玩一个类,但它似乎没有很多优点 - 除了你可以自定义一个键错误异常,以便错误消息告诉你哪个键在哪个深度丢失。

            class Drilldown:
                def __init__(self, d, path):
                    #self.final = reduce(getitem, path, d)
                    self.final = d
                    for i, item in enumerate(path, 1):
                        try:
                            self.final = self.final[item]
                        except KeyError as e:
                            msg = ''.join('[{}]' for _ in range(i))
                            msg = msg.format(*path[:i])
                            msg = 'The last key in the path "{}" does not exist'.format(msg)
                            e.args = [msg]
                            raise
                def __call__(self, item):
                    return self.final[item]
                def __setitem__(self, item, value):
                    self.final[item] = value
                def __getitem__(self, item):
                    return self.final[item]
                def __str__(self):
                    return str(self.final)
                def __repr__(self):
                    return repr(self.final)
            
            >>> z = 19
            >>> items = [1,2,z]
            >>> q = Drilldown(d,items)
            Traceback (most recent call last):
              File "<pyshell#68>", line 1, in <module>
                q = Drilldown(d,items)
              File "C:\pyProjects33\tmp.py", line 32, in __init__
                self.final = self.final[item]
            KeyError: 'The last key in the path "[1][2][19]" does not exist'
            
            >>> 
            >>> #normal usage
            >>> items = [1,2,3]
            >>> q = Drilldown(d,items)
            >>> d
            {1: {2: {3: {4: 5}}}}
            >>> q
            {4: 5}
            >>> q(4)
            5
            >>> q[4]
            5
            >>> q[4] += 20
            >>> q
            {4: 25}
            >>> d
            {1: {2: {3: {4: 25}}}}
            >>> q['foo'] = '99'
            >>> q
            {4: 25, 'foo': '99'}
            >>> d
            {1: {2: {3: {4: 25, 'foo': '99'}}}}
            >>> 
            

            【讨论】:

              猜你喜欢
              • 2021-12-29
              • 1970-01-01
              • 2017-04-30
              • 1970-01-01
              • 1970-01-01
              • 2021-05-28
              • 2011-02-01
              • 1970-01-01
              • 2018-11-30
              相关资源
              最近更新 更多