更新不同深度的嵌套字典的值

2025-01-03 08:41:00
admin
原创
88
摘要:问题描述:我正在寻找一种方法来dictionary1用 dict 的内容更新 dictupdate而不覆盖levelAdictionary1 = { "level1": { "level2": {"levelA": 0, &q...

问题描述:

我正在寻找一种方法来dictionary1用 dict 的内容更新 dictupdate而不覆盖levelA

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

我知道更新会删除 level2 中的值,因为它正在更新最低键 level1。

鉴于 dictionary1 和 update 可以有任意长度,我该如何解决这个问题?


解决方案 1:

@FM 的答案有正确的总体思路,即递归解决方案,但编码有些奇怪,并且至少有一个错误。我建议:

Python 2:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

Python 3:

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

当“更新”有一个项目时,就会出现错误kv其中vdict并且k最初不是被更新字典中的键——@FM 的代码“跳过”了更新的这一部分(因为它在一个空的新值上执行它,这个新dict值没有保存或返回到任何地方,只是在递归调用返回时丢失)。

if我的其他更改很小:当/else构造.get可以更快、更干净地完成相同的工作时,没有理由这样做,并且isinstance最好将其应用于抽象基类(而不是具体基类)以实现通用性。

解决方案 2:

如果你碰巧使用pydantic(顺便说一下,这是一个很棒的库),那么你可以使用它的一个实用方法:

from pydantic.utils import deep_update

dictionary1 = deep_update(dictionary1, update)

更新:参考代码,正如@Jorgu指出的那样。如果不想安装 pydantic,代码很短,可以复制,只要有足够的许可证兼容性。

解决方案 3:

这道题花了我一点时间,但多亏了 @Alex 的帖子,他填补了我遗漏的空白。但是,我遇到了一个问题,如果递归中的值dict恰好是list,那么我会分享并扩展他的答案。

import collections

def update(orig_dict, new_dict):
    for key, val in 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.get(key, []) + val)
        else:
            orig_dict[key] = new_dict[key]
    return orig_dict

解决方案 4:

{}与接受的解决方案相同,但变量命名、文档字符串更清晰,并修复了值不会覆盖的错误。

import collections


def deep_update(source, overrides):
    """
    Update a nested dictionary or similar mapping.
    Modify ``source`` in place.
    """
    for key, value in overrides.iteritems():
        if isinstance(value, collections.Mapping) and value:
            returned = deep_update(source.get(key, {}), value)
            source[key] = returned
        else:
            source[key] = overrides[key]
    return source

以下是一些测试用例:

def test_deep_update():
    source = {'hello1': 1}
    overrides = {'hello2': 2}
    deep_update(source, overrides)
    assert source == {'hello1': 1, 'hello2': 2}

    source = {'hello': 'to_override'}
    overrides = {'hello': 'over'}
    deep_update(source, overrides)
    assert source == {'hello': 'over'}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': 'over'}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 'over', 'no_change': 1}}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': {}}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': {}, 'no_change': 1}}

    source = {'hello': {'value': {}, 'no_change': 1}}
    overrides = {'hello': {'value': 2}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 2, 'no_change': 1}}

该函数可以在charlatan包中使用charlatan.utils

解决方案 5:

@Alex 的答案很好,但在用字典替换整数等元素时不起作用,例如update({'foo':0},{'foo':{'bar':1}})。此更新解决了此问题:

import collections
def update(d, u):
    for k, v in u.iteritems():
        if isinstance(d, collections.Mapping):
            if isinstance(v, collections.Mapping):
                r = update(d.get(k, {}), v)
                d[k] = r
            else:
                d[k] = u[k]
        else:
            d = {k: u[k]}
    return d

update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})

解决方案 6:

这是一个递归字典合并的不可变版本,以防有人需要它。

根据@Alex Martelli 的回答。

Python 3.x:

from collections.abc import Mapping
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.items():
        if isinstance(value, Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

Python 2.x:

import collections
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.iteritems():
        if isinstance(value, collections.Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

解决方案 7:

这个问题很老了,但我在寻找“深度合并”解决方案时遇到了这个问题。上面的答案启发了我接下来的内容。我最终自己写了这个问题,因为我测试的所有版本都有错误。忽略的关键点是,在两个输入字典的某个任意深度,对于某个键 k,当 d[k] 或 u[k] 不是字典时,决策树是有缺陷的。

此外,该解决方案不需要递归,这与dict.update()工作原理和返回更加对称None

import collections
def deep_merge(d, u):
   """Do a deep merge of one dict into another.

   This will update d with values in u, but will not delete keys in d
   not found in u at some arbitrary depth of d. That is, u is deeply
   merged into d.

   Args -
     d, u: dicts

   Note: this is destructive to d, but not u.

   Returns: None
   """
   stack = [(d,u)]
   while stack:
      d,u = stack.pop(0)
      for k,v in u.items():
         if not isinstance(v, collections.Mapping):
            # u[k] is not a dict, nothing to merge, so just set it,
            # regardless if d[k] *was* a dict
            d[k] = v

        else:
            # note: u[k] is a dict
            if k not in d:
                # add new key into d
                d[k] = v
            elif not isinstance(d[k], collections.Mapping):
                # d[k] is not a dict, so just set it to u[k],
                # overriding whatever it was
                d[k] = v
            else:
                # both d[k] and u[k] are dicts, push them on the stack
                # to merge
                stack.append((d[k], v))

解决方案 8:

只需使用python-benedict (我做到了),它有一个merge(deepupdate)实用方法和许多其他方法。它适用于 python 2 / python 3,并且经过了充分测试。

from benedict import benedict

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

安装:pip install python-benedict

文档:https ://github.com/fabiocaccamo/python-benedict

注:我是这个项目的作者

解决方案 9:

对@Alex 的答案进行了细微改进,可以更新不同深度的字典,并限制更新深入原始嵌套字典的深度(但更新字典的深度不受限制)。仅测试了少数情况:

def update(d, u, depth=-1):
    """
    Recursively merge or update dict-like objects. 
    >>> update({'k1': {'k2': 2}}, {'k1': {'k2': {'k3': 3}}, 'k4': 4})
    {'k1': {'k2': {'k3': 3}}, 'k4': 4}
    """

    for k, v in u.iteritems():
        if isinstance(v, Mapping) and not depth == 0:
            r = update(d.get(k, {}), v, depth=max(depth - 1, -1))
            d[k] = r
        elif isinstance(d, Mapping):
            d[k] = u[k]
        else:
            d = {k: u[k]}
    return d

解决方案 10:

下面的代码应该可以update({'k1': 1}, {'k1': {'k2': 2}})正确解决@Alex Martelli 的答案中的问题。

def deepupdate(original, update):
    """Recursively update a dict.

    Subdict's won't be overwritten but also updated.
    """
    if not isinstance(original, abc.Mapping):
        return update
    for key, value in update.items():
        if isinstance(value, abc.Mapping):
            original[key] = deepupdate(original.get(key, {}), value)
        else:
            original[key] = value
    return original

解决方案 11:

我使用了@Alex Martelli 建议的解决方案,但失败了

TypeError 'bool' object does not support item assignment

当两个字典的数据类型在某种程度上有所不同时。

如果在同一级别,字典的元素d只是一个标量(即Bool),而字典的元素u仍然是字典,则重新分配会失败,因为无法将字典分配到标量(如True[k])。

一个附加条件修复了以下问题:

from collections import Mapping

def update_deep(d, u):
    for k, v in u.items():
        # this condition handles the problem
        if not isinstance(d, Mapping):
            d = u
        elif isinstance(v, Mapping):
            r = update_deep(d.get(k, {}), v)
            d[k] = r
        else:
            d[k] = u[k]

    return d

解决方案 12:

感谢hobs对Alex 的 回答的评论。确实update({'k1': 1}, {'k1': {'k2': 2}})会导致TypeError: 'int' object does not support item assignment.

我们应该在函数开始时检查输入值的类型。因此,我建议使用以下函数,它应该可以解决此问题(以及其他问题)。

Python 3:

from collections.abc import Mapping


def deep_update(d1, d2):
    if all((isinstance(d, Mapping) for d in (d1, d2))):
        for k, v in d2.items():
            d1[k] = deep_update(d1.get(k), v)
        return d1
    return d2

解决方案 13:

在这两个答案中,作者似乎都不理解更新存储在字典中的对象的概念,甚至不理解迭代字典项(而不是键)的概念。所以我不得不写一个不会进行毫无意义的重复字典存储和检索的答案。假设字典存储其他字典或简单类型。

def update_nested_dict(d, other):
    for k, v in other.items():
        if isinstance(v, collections.Mapping):
            d_v = d.get(k)
            if isinstance(d_v, collections.Mapping):
                update_nested_dict(d_v, v)
            else:
                d[k] = v.copy()
        else:
            d[k] = v

或者更简单的适用于任何类型:

def update_nested_dict(d, other):
    for k, v in other.items():
        d_v = d.get(k)
        if isinstance(v, collections.Mapping) and isinstance(d_v, collections.Mapping):
            update_nested_dict(d_v, v)
        else:
            d[k] = deepcopy(v) # or d[k] = v if you know what you're doing

解决方案 14:

更新@Alex Martelli 的答案以修复其代码中的错误,从而使解决方案更加健壮:

def update_dict(d, u):
    for k, v in u.items():
        if isinstance(v, collections.Mapping):
            default = v.copy()
            default.clear()
            r = update_dict(d.get(k, default), v)
            d[k] = r
        else:
            d[k] = v
    return d

关键是我们经常想在递归时创建相同的类型v.copy().clear(),所以这里我们使用但不是。如果这里的类型可以有不同类型的s,{}这尤其有用。dict`collections.defaultdict`default_factory

还请注意,u.iteritems()已更改u.items()Python3

解决方案 15:

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

使用dictcollections.Mapping

解决方案 16:

我建议用 替换{}type(v)()以便传播存储在 中u但不存在于 中的任何 dict 子类的对象类型d。例如,这将保留 collections.OrderedDict 等类型:

Python 2:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, type(v)()), v)
        else:
            d[k] = v
    return d

Python 3:

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, type(v)()), v)
        else:
            d[k] = v
    return d

解决方案 17:

您可能像今天一样偶然发现了一个非标准字典,它没有 iteritems 属性。在这种情况下,很容易将这种类型的字典解释为标准字典。例如:
Python 2.7:

    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()

Python 3.8:

    def update(orig_dict, new_dict):
        orig_dict=dict(orig_dict)
        for key, val in dict(new_dict).items():
            if isinstance(val, collections.abc.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 collections
    import multiprocessing
    d=multiprocessing.Manager().dict({'sample':'data'})
    u={'other': 1234, "deeper": {'very': 'deep'}}

    x=update(d, u)
    x.items()

解决方案 18:

我知道这个问题已经很老了,但我仍然发布我在更新嵌套字典时所做的事情。我们可以利用 python 中字典通过引用传递的事实,假设键的路径已知并且以点分隔。外汇,如果我们有一个名为 data 的字典:

{
"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(obj, path, value):
    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")

这将正确更新字典。

解决方案 19:

我制作了一个简单的函数,其中你提供键、新值和字典作为输入,然后它使用值递归更新它:

def update(key,value,dictionary):
    if key in dictionary.keys():
        dictionary[key] = value
        return
    dic_aux = []
    for val_aux in dictionary.values():
        if isinstance(val_aux,dict):
            dic_aux.append(val_aux)
    for i in dic_aux:
        update(key,value,i)
    for [key2,val_aux2] in dictionary.items():
        if isinstance(val_aux2,dict):
            dictionary[key2] = val_aux2

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

#output: {'level1': {'level2': {'levelA': 0, 'levelB': 10}}}

希望它能解答。

解决方案 20:

是的!还有另一种解决方案。我的解决方案在检查的键上有所不同。在所有其他解决方案中,我们只查看 中的键dict_b。但在这里,我们查看两个字典的并集。

随心所欲地处理

def update_nested(dict_a, dict_b):
    set_keys = set(dict_a.keys()).union(set(dict_b.keys()))
    for k in set_keys:
        v = dict_a.get(k)
        if isinstance(v, dict):
            new_dict = dict_b.get(k, None)
            if new_dict:
                update_nested(v, new_dict)
        else:
            new_value = dict_b.get(k, None)
            if new_value:
                dict_a[k] = new_value

解决方案 21:

如果您想替换“带有数组的完整嵌套字典”,您可以使用以下代码片段:

它将用“new_value”替换任何“old_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

解决方案 22:

使用递归的另一种方法:

def updateDict(dict1,dict2):
    keys1 = list(dict1.keys())
    keys2= list(dict2.keys())
    keys2 = [x for x in keys2 if x in keys1]
    for x in keys2:
        if (x in keys1) & (type(dict1[x]) is dict) & (type(dict2[x]) is dict):
            updateDict(dict1[x],dict2[x])
        else:
            dict1.update({x:dict2[x]})
    return(dict1)

解决方案 23:

感谢:@Gustavo Alves Casqueiro 的原始答案

说实话,我本来希望使用一个可以为我完成繁重工作的库,但我就是找不到可以满足我需求的东西。

我只是对这个函数添加了几个额外的检查。

lists我已经包含了对内的检查dict,并添加了一个嵌套名称的参数,以便在 OUTER 中可能有另一个同名的KEY时dict正确更新嵌套的KEY。dict`dict`

更新功能:

def update(dictionary: dict[str, any], key: str, value: any, nested_dict_name: str = None) -> dict[str, any]:
    if not nested_dict_name:  # if current (outermost) dict should be updated
        if key in dictionary.keys():  # check if key exists in current dict
            dictionary[key] = value
            return dictionary
    else:  # if nested dict should be updated
        if nested_dict_name in dictionary.keys():  # check if dict is in next layer
            if isinstance(dictionary[nested_dict_name], dict):
                if key in dictionary[nested_dict_name].keys():  # check if key exists in current dict
                    dictionary[nested_dict_name][key] = value
                    return dictionary
            if isinstance(dictionary[nested_dict_name], list):
                list_index = random.choice(range(len(dictionary[nested_dict_name])))  # pick a random dict from the list

                if key in dictionary[nested_dict_name][list_index].keys():  # check if key exists in current dict
                    dictionary[nested_dict_name][list_index][key] = value
                    return dictionary

    dic_aux = []

    # this would only run IF the above if-statement was not able to identity and update a dict
    for val_aux in dictionary.values():
        if isinstance(val_aux, dict):
            dic_aux.append(val_aux)

    # call the update function again for recursion
    for i in dic_aux:
        return update(dictionary=i, key=key, value=value, nested_dict_name=nested_dict_name)

原文:

{
    "level1": {
        "level2": {
            "myBool": "Original",
            "myInt": "Original"
        },
        "myInt": "Original",
        "myBool": "Original"
    },
    "myStr": "Original",
    "level3": [
        {
            "myList": "Original",
            "myInt": "Original",
            "myBool": "Original"
        }
    ],
    "level4": [
        {
            "myList": "Original",
            "myInt": "UPDATED",
            "myBool": "Original"
        }
    ],
    "level5": {
        "level6": {
            "myBool": "Original",
            "myInt": "Original"
        },
        "myInt": "Original",
        "myBool": "Original"
    }
}

更新数据(使用pytest):

@pytest.fixture(params=[(None, 'myStr', 'UPDATED'),
                        ('level1', 'myInt', 'UPDATED'),
                        ('level2', 'myBool', 'UPDATED'),
                        ('level3', 'myList', 'UPDATED'),
                        ('level4', 'myInt', 'UPDATED'),
                        ('level5', 'myBool', 'UPDATED')])
def sample_data(request):
    return request.param

在这个较小的用例中,该'UPDATED'参数没有意义(因为我可以对其进行硬编码),但为了在读取日志时简单起见,我不想看到多种数据类型,只是让它显示一个'UPDATED'字符串。

测试:

@pytest.mark.usefixtures('sample_data')
def test_this(sample_data):
    nested_dict, param, update_value = sample_data

    if nested_dict is None:
        print(f'
Dict Value: Level0
Param: {param}
Update Value: {update_value}')
    else:
        print(f'
Dict Value: {nested_dict}
Param: {param}
Update Value: {update_value}')

    # initialise data dict
    data_object = # insert data here (see example dict above)

    # first print as is
    print(f'
Original Dict:
{data_object}')

    update(dictionary=data_object,
           key=param,
           value=update_value,
           nested_dict_name=nested_dict)

    # print updated
    print(f'
Updated Dict:
{data_object}')

当你有这样的字典时,有一个警告:

{
    "level1": {
        "level2": {
            "myBool": "Original"
        },
        "myBool": "Original"
    },
    "level3": {
        "level2": {
            "myBool": "Original"
        },
        "myInt": "Original"
    }
}

其中level2level1AND之下level3。这需要使用list或 以及 并传入外部AND 内部( )nested_dict_name的名称,然后以某种方式循环遍历值以找到。dict`dict['level5', 'level2']dict`

但是,由于我所使用的数据对象还没有遇到这个问题,所以我没有花时间去尝试解决这个“问题”。

解决方案 24:

将您的词典转换为NestedDict

from ndicts.ndicts import NestedDict

dictionary1 = {'level1': {'level2': {'levelA': 0, 'levelB': 1}}}
update = {'level1': {'level2': {'levelB': 10}}}

nd, nd_update = NestedDict(dictionary1), NestedDict(update)

然后只需使用更新

>>> nd.update(nd_update)
>>> nd
NestedDict({'level1': {'level2': {'levelA': 0, 'levelB': 10}}})

如果你需要字典形式的结果nd.to_dict()

安装ndicts pip install ndicts

解决方案 25:

d是需要更新的字典,u是 dict-updater。

def recursively_update_dict(d: dict, u: dict):
    for k, v in u.items():
        if isinstance(v, dict):
            d.setdefault(k, {})
            recursively_update_dict(d[k], v)
        else:
            d[k] = v

或者对于 defaultdict

from collections import defaultdict

def recursively_update_defaultdict(d: defaultdict[dict], u: dict):
    for k, v in u.items():
        if isinstance(v, dict):
            recursively_update_dict(d[k], v)
        else:
            d[k] = v

解决方案 26:

基本解决方案(以防有人来这里寻找)

dictionary1 = {
    "level1": {
        "level2": {"levelA": 0, "levelB": 1}
    }
}

dictionary1.update({
    "level1": {
        "level2": {
            **dictionary1["level1"]["level2"],
            "levelB": 10
        }
    }
})

结果:

{'level1': {'level2': {'levelA': 0, 'levelB': 10}}}

解决方案 27:

以下是我使用的:

from collections.abc import MutableMapping as Map

def merge(d, v):
    """
    Merge two dictionaries.

    Merge dict-like `v` into dict-like `d`. In case keys between them
    are the same, merge their sub-dictionaries. Otherwise, values in  
    `v` overwrite `d`.
    """
    for key in v:
        if key in d and isinstance(d[key], Map) and isinstance(v[key], Map):
            d[key] = merge(d[key], v[key])
        else:
            d[key] = v[key]
    return d
merge(dictionary1, update)
print(dictionary1)

>>> {'level1': {'level2': {'levelA': 0, 'levelB': 10}}}

解决方案 28:

@kepler 的回答对我有帮助,但是当我跑步时

from pydantic.utils import deep_update
dict1 = deep_update(dict1, dict2)

出现警告:

UserWarning: `pydantic.utils:deep_update` has been removed. We are importing from `pydantic.v1.utils:deep_update` instead.See the migration guide for more details: https://docs.pydantic.dev/latest/migration/
  f'`{import_path}` has been removed. We are importing from `{new_location}` instead.'

因此我将导入命令改为

from pydantic.v1.utils import deep_update

解决方案 29:

dictionary1 = {
    "level1": {
        "level2": {"levelA": 0, "levelB": 1}
    }
}
update = {
    "level1": {
        "level2": {"levelB": 10}
    }
}

from pydash import py_
print(py_.merge(dictionary1, update))

输出:{'level1':{'level2':{'levelA':0,'levelB':10}}}

解决方案 30:

部分感谢这里的答案,我能够想出一个向字典中添加项目的解决方案,包括将项目添加到字典中的列表值中(如果它们尚未在列表中)。

Python 3:

import collections.abc

def dict_update(d, u, fixed=False):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            if k in d.keys() or not fixed:
                d[k] = dict_update(d.get(k, {}), v, fixed=fixed)
        elif isinstance(v, list):
            if k in d.keys() or not fixed:
                # Iterate through list value and add item if not already in list
                for i in v:
                    if i not in d.get(k, []):
                        d[k] = d.get(k, []) + [i]
        else:
            if k in d.keys() or not fixed:
                d[k] = v
    return d
dictionary1 = {
    "level1": {
        "level2": {"levelA": 0, "levelB": 1},
        "level3": ["itemA", "itemB"]
    }
}

update = {
    "level1": {
        "level2": {"levelB": 10},
        "level3": ["itemC"]
    }
}

updated_dict = dict_update(dictionary1, update, fixed=False)
print(updated_dict)

>>> {'level1': {'level2': {'levelA': 0, 'levelB': 10}, 'level3': ['itemA', 'itemB', 'itemC']}}

如果fixed=True,输入字典d将是固定的,并且只有当键已经存在于原始字典中时才会更新值,因此不会添加新的键。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用