Python中处理深度嵌套字典的便捷方式

7

我在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

并且仍然需要编辑字典吗?希望这样说得通。

这是设置单个事物最快的方法。如果您有更多要设置的数据,可以抓住最低公共分母并从那里开始工作。 - tdelaney
7个回答

6
与 @fferri 类似,您始终需要在一个 列表中指定项目。使用 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'}}}}
>>> 

4
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 的内容。


3
是的,您可以。
>>> dict1 = {'foo':{'bar':{'baz':0}}}
>>> dict2 = dict1['foo']['bar']
>>> dict2['baz'] = 1
>>> dict1
{'foo': {'bar': {'baz': 1}}} # dict1 has been modified

2
你能做这样的事吗?
thing = {1: {2: {3: {4: {'hello': 'world'}}}}}
a = thing[1]
b = a[2]
c = b[3]
d = c[4]
print(d) # {'hello': 'world'}

2

由于字典是可变的,因此实际上它将按照您预期的方式发生更改:

>>> 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中,可变对象是按引用传递的,而不是作为副本传递的(有很多关于这个的好文章,所以不再详述)。
然而,值得注意的是,您可能实际上并不想更改原始字典,因为它可能会对使用此变量的其他代码产生不良影响(这取决于您的代码库)。在这种情况下,我通常会复制我需要更改的数据以避免副作用。
>>> 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'}}

2
如果您有一些“固定”的键,您可以创建一个函数:
考虑以下示例:
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] ... 或许还有其他内容。

0
你可以考虑使用一个 NestedDict。这里是一个比较。
# dictionary
master_dictionary['sub_categories'][sub_cat_name]['attributes'][attribute_name]['special_type']['nested_children'][child_cat_name][color] = blue

# NestedDict
key = (
    'sub_categories', 
    sub_cat_name, 
    'attributes', 
    attribute_name, 
    'special_type', 
    'nested_children', 
    child_cat_name, 
    color
)
master_dictionary[key] = blue

你可以在 PyPi 上的 ndicts 中找到 NestedDict

pip install ndicts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接