Как сделать динамические c вложенные обновления в dict? - PullRequest
0 голосов
/ 13 января 2020

У меня есть требование обновлять / объединять вложенный дочерний элемент dict. Я пробовал dict.update, но он лишает родного брата (get_users в приведенном ниже примере).

Я могу обновить dict как tree['endpoints']['get_tickets']['handlers']['after'] = 'new_after_handler', но эти ключи будут динамическими c, Исходя из строки, есть идеи, как этого добиться?

Так что я в основном хочу пройти тест ниже, конечно, endpoints.get_tickets.handlers будет Dynami c.

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 ]

2 голосов
/ 13 января 2020

Вы можете сделать что-то вроде этого:

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
0 голосов
/ 13 января 2020

В вашем Merger.merge методе вы можете конвертировать source в collections.defaultdict(dict). Затем вы можете перебрать третий параметр ("endpoints.get_tickets.handlers".split('.')) и итерационно go до необходимого уровня глубины, а затем обновить эту часть.

Пример:

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
...