Обновить значение вложенного словаря различной глубины - PullRequest
135 голосов
/ 13 июля 2010

Я ищу способ обновить словарь dict1 содержимым обновления dict без перезаписи уровня A

dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}

Я знаю, что обновление удаляет значения на уровне2, потому что обновляется самый низкий ключ уровня1.

Как я могу решить эту проблему, учитывая, что словарь1 и обновление могут иметь любую длину?

Ответы [ 16 ]

1 голос
/ 21 марта 2019

Я знаю, что этот вопрос довольно старый, но все еще публикует информацию о том, что я делаю, когда мне нужно обновить вложенный словарь.Мы можем использовать тот факт, что dicth передаются по ссылке в python. Предполагая, что путь к ключу известен и разделен точками.Форекс, если у нас есть данные с именем dict:

{
"log_config_worker": {
    "version": 1, 
    "root": {
        "handlers": [
            "queue"
        ], 
        "level": "DEBUG"
    }, 
    "disable_existing_loggers": true, 
    "handlers": {
        "queue": {
            "queue": null, 
            "class": "myclass1.QueueHandler"
        }
    }
}, 
"number_of_archived_logs": 15, 
"log_max_size": "300M", 
"cron_job_dir": "/etc/cron.hourly/", 
"logs_dir": "/var/log/patternex/", 
"log_rotate_dir": "/etc/logrotate.d/"
}

И мы хотим обновить класс очереди, путь к ключу будет - log_config_worker.handlers.queue.class

Мы можем использовать следующую функциючтобы обновить значение:

def get_updated_dict(dict_to_update, path, value):
obj = dict_to_update
key_list = path.split(".")

for k in key_list[:-1]:
    obj = obj[k]

obj[key_list[-1]] = value

get_updated_dict(data, "log_config_worker.handlers.queue.class", "myclass2.QueueHandler")

Это правильно обновит словарь.

1 голос
/ 06 августа 2015

Может случиться так, что вы наткнетесь на нестандартный словарь, как я сегодня, у которого нет атрибута iteritems.В этом случае этот тип словаря легко интерпретировать как стандартный словарь.Например:

import collections
def update(orig_dict, new_dict):
    for key, val in dict(new_dict).iteritems():
        if isinstance(val, collections.Mapping):
            tmp = update(orig_dict.get(key, { }), val)
            orig_dict[key] = tmp
        elif isinstance(val, list):
            orig_dict[key] = (orig_dict[key] + val)
        else:
            orig_dict[key] = new_dict[key]
    return orig_dict

import multiprocessing
d=multiprocessing.Manager().dict({'sample':'data'})
u={'other': 1234}

x=update(d, u)
x.items()
0 голосов
/ 17 июня 2019

Если вы хотите заменить «полный вложенный словарь на массивы», вы можете использовать этот фрагмент:

Он заменит любое «old_value» на «new_value».Это примерно воссоздание словаря в глубину.Он может даже работать с List или Str / int, заданными в качестве входного параметра первого уровня.

def update_values_dict(original_dict, future_dict, old_value, new_value):
    # Recursively updates values of a nested dict by performing recursive calls

    if isinstance(original_dict, Dict):
        # It's a dict
        tmp_dict = {}
        for key, value in original_dict.items():
            tmp_dict[key] = update_values_dict(value, future_dict, old_value, new_value)
        return tmp_dict
    elif isinstance(original_dict, List):
        # It's a List
        tmp_list = []
        for i in original_dict:
            tmp_list.append(update_values_dict(i, future_dict, old_value, new_value))
        return tmp_list
    else:
        # It's not a dict, maybe a int, a string, etc.
        return original_dict if original_dict != old_value else new_value
0 голосов
/ 01 ноября 2018
def update(value, nvalue):
    if not isinstance(value, dict) or not isinstance(nvalue, dict):
        return nvalue
    for k, v in nvalue.items():
        value.setdefault(k, dict())
        if isinstance(v, dict):
            v = update(value[k], v)
        value[k] = v
    return value

использование dict или collections.Mapping

0 голосов
/ 26 октября 2018

Если вы хотите однострочник:

{**dictionary1, **{'level1':{**dictionary1['level1'], **{'level2':{**dictionary1['level1']['level2'], **{'levelB':10}}}}}}
0 голосов
/ 13 июля 2010

Это немного в стороне, но вам действительно нужны вложенные словари?В зависимости от проблемы, иногда может быть достаточно плоского словаря ... и хорошо выглядеть:

>>> dict1 = {('level1','level2','levelA'): 0}
>>> dict1['level1','level2','levelB'] = 1
>>> update = {('level1','level2','levelB'): 10}
>>> dict1.update(update)
>>> print dict1
{('level1', 'level2', 'levelB'): 10, ('level1', 'level2', 'levelA'): 0}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...