如何对字典进行动态嵌套更新?

时间:2020-01-13 17:45:47

标签: python dictionary

我有一个要求,我必须更新/合并字典的嵌套子级。我已经尝试过dict.update,但是它会删除兄弟姐妹(在下面的示例中为get_users)。

我可以更新tree['endpoints']['get_tickets']['handlers']['after'] = 'new_after_handler'之类的字典,但是那些字典键是动态的,来自字符串,不知道如何实现?

所以我基本上想通过下面的测试,当然endpoints.get_tickets.handlers是动态的。

def test_partial_merge(self):
    source = {
        "name": "tucktock",
        "endpoints": {
            "get_tickets": {
                "path": "tickets",
                "handlers": {
                    "after": "after_handler",
                    "after_each": "after_each_handler"
                }
            },
            "get_users": {},
        },
    }
    merging = {
        "after": "new_after_handler",
    }
    expected = {
        "name": "tucktock",
        "endpoints": {
            "get_tickets": {
                "path": "tickets",
                "handlers": {
                    "after": "new_after_handler",
                    "after_each": "after_each_handler"
                }
            },
            "get_users": {},
        },
    }

    merger = Merger()
    result = merger.merge(source, merging, "endpoints.get_tickets.handlers")
    self.assertEqual(expected, result)

2 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

source = {
    "name": "tucktock",
    "endpoints": {
        "get_tickets": {
            "path": "tickets",
            "handlers": {
                "after": "after_handler",
                "after_each": "after_each_handler"
            }
        },
        "get_users": {},
    },
}

merging = {
    "after": "new_after_handler",
}
expected = {
    "name": "tucktock",
    "endpoints": {
        "get_tickets": {
            "path": "tickets",
            "handlers": {
                "after": "new_after_handler",
                "after_each": "after_each_handler"
            }
        },
        "get_users": {},
    },
}


def merge(a, b, dict_path):  # modifies a in place
    for key in dict_path:
        a = a[key]
    a.update(b)


merge(source, merging, "endpoints.get_tickets.handlers".split('.'))
print(source == expected)

>>> True

答案 1 :(得分:0)

在您的Merger.merge方法中,您可以将source转换为collections.defaultdict(dict)。然后,您可以遍历第三个参数("endpoints.get_tickets.handlers".split('.')),并迭代到所需的深度级别,然后更新此部分。

示例:

def merge(source, merging, path):
    result = defaultdict(dict)
    result.update(source)
    current_part = result
    for key in path.split('.'):
        current_level = current_level[key]
    current_level.update(merging)
    return result