Python 如何更新嵌套在另一个目录中的dict?

Python 如何更新嵌套在另一个目录中的dict?,python,dictionary,recursion,Python,Dictionary,Recursion,我有以下原文: {'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'" }, 'calibration': True, 'target_v

我有以下原文:

{'data_extraction': {'if_extraction': False,
  'path_data': 'data_extraction/extractions.sql',
  'set_params': {'START_DT': "'201901'",
   'END_DT': "'202104'"
                         },
  'calibration': True,
  'target_variable': 'unsure'}}
我想用以下命令替换set params位:

dict1= {'set_params': {'START_DT': "'201001'",
   'END_DT': "'201004'"
}}
我从一个类似的问题中得到了这个代码:

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

update(original,dict1)
将其应用于上面,我得到:

 {'data_extraction': {'if_extraction': False,
          'path_data': 'data_extraction/extractions.sql',
          'set_params': {'START_DT': "'201901'",
           'END_DT': "'202104'"
                                 },
          'calibration': True,
          'target_variable': 'unsure'},
           'set_params': {'START_DT': "'201001'",
            'END_DT': "'201004'" }}

因此,它没有替换,而是在末尾附加了替换dict。如何更新dict中的值,以便在传递另一个dict时,它会替换dict1?我做错了什么?

在dict中,当您将某个内容添加到一个不存在的键上时,它会被追加,然后添加内容。如果你想替换一些密钥,你必须先删除它。
使用pop键删除您的dict.pop键,然后您可以正常添加另一个键。

在dict中,当您向一个不存在的键添加某个内容时,会追加该内容,然后添加内容。如果你想替换一些密钥,你必须先删除它。
对要删除的yourdict.pop键使用pop,然后您可以正常添加另一个键。

现在Python dict有一个更新方法,可以从另一个dict更新。请确保指定要更新和更新的相应dict

original['data_extraction']['set_params'].update(dict1['set_params'])
或者可能

original['data_extraction'].update(dict1)

如果dict1中除了“set_params”之外还有其他键,并且您也希望更新这些键。

现在Python dict有一个更新方法可以从另一个dict更新。请确保指定要更新和更新的相应dict

original['data_extraction']['set_params'].update(dict1['set_params'])
或者可能

original['data_extraction'].update(dict1)
如果在dict1中除了“set_params”之外还有其他键,并且您也希望更新这些键。

使用dict.update的递归函数。这样,在使用多级字典时,就不必指定键

def update_dict(source_dict, dict1):
    for key in source_dict:
        if key in dict1.keys():
            source_dict.update(dict1)
        elif isinstance(source_dict[key],dict):
            update_dict(source_dict[key], dict1)


source_dict = {'data_extraction': {'if_extraction': False,
      'path_data': 'data_extraction/extractions.sql',
      'set_params': {'START_DT': "'201901'",
       'END_DT': "'202104'"},
      'calibration': True,
      'target_variable': 'unsure'}}

dict1= {'set_params': {'START_DT': "'201001'",
   'END_DT': "'201004'"
}}

update_dict(source_dict, dict1)

print(source_dict)

>> 
{'data_extraction': {'if_extraction': False,
  'path_data': 'data_extraction/extractions.sql',
  'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"},
  'calibration': True,
  'target_variable': 'unsure'}}
from copy import deepcopy

def update(d, u):
    r = deepcopy(d)
    for k, v in r.items():
        if type(v) is dict:
            for _k, _v in v.items():
                if _k in u:
                    r[k][_k] = u[_k]
        elif k in u:
            r[k] = u[k]
    return r


a = {'data_extraction':{'if_extraction': False,
                         'path_data': 'data_extraction/extractions.sql',
                         'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"},
                         'calibration': True,
                         'target_variable': 'unsure'}
     }

b = {'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}}

c = update(a, b)

print(a, '\n')
print(b, '\n')
print(c, '\n')
将递归函数与dict.update一起使用。这样,在使用多级字典时,就不必指定键

def update_dict(source_dict, dict1):
    for key in source_dict:
        if key in dict1.keys():
            source_dict.update(dict1)
        elif isinstance(source_dict[key],dict):
            update_dict(source_dict[key], dict1)


source_dict = {'data_extraction': {'if_extraction': False,
      'path_data': 'data_extraction/extractions.sql',
      'set_params': {'START_DT': "'201901'",
       'END_DT': "'202104'"},
      'calibration': True,
      'target_variable': 'unsure'}}

dict1= {'set_params': {'START_DT': "'201001'",
   'END_DT': "'201004'"
}}

update_dict(source_dict, dict1)

print(source_dict)

>> 
{'data_extraction': {'if_extraction': False,
  'path_data': 'data_extraction/extractions.sql',
  'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"},
  'calibration': True,
  'target_variable': 'unsure'}}
from copy import deepcopy

def update(d, u):
    r = deepcopy(d)
    for k, v in r.items():
        if type(v) is dict:
            for _k, _v in v.items():
                if _k in u:
                    r[k][_k] = u[_k]
        elif k in u:
            r[k] = u[k]
    return r


a = {'data_extraction':{'if_extraction': False,
                         'path_data': 'data_extraction/extractions.sql',
                         'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"},
                         'calibration': True,
                         'target_variable': 'unsure'}
     }

b = {'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}}

c = update(a, b)

print(a, '\n')
print(b, '\n')
print(c, '\n')

你就快到了。。。在这个实现中,我使用deepcopy来避免覆盖原始字典

def update_dict(source_dict, dict1):
    for key in source_dict:
        if key in dict1.keys():
            source_dict.update(dict1)
        elif isinstance(source_dict[key],dict):
            update_dict(source_dict[key], dict1)


source_dict = {'data_extraction': {'if_extraction': False,
      'path_data': 'data_extraction/extractions.sql',
      'set_params': {'START_DT': "'201901'",
       'END_DT': "'202104'"},
      'calibration': True,
      'target_variable': 'unsure'}}

dict1= {'set_params': {'START_DT': "'201001'",
   'END_DT': "'201004'"
}}

update_dict(source_dict, dict1)

print(source_dict)

>> 
{'data_extraction': {'if_extraction': False,
  'path_data': 'data_extraction/extractions.sql',
  'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"},
  'calibration': True,
  'target_variable': 'unsure'}}
from copy import deepcopy

def update(d, u):
    r = deepcopy(d)
    for k, v in r.items():
        if type(v) is dict:
            for _k, _v in v.items():
                if _k in u:
                    r[k][_k] = u[_k]
        elif k in u:
            r[k] = u[k]
    return r


a = {'data_extraction':{'if_extraction': False,
                         'path_data': 'data_extraction/extractions.sql',
                         'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"},
                         'calibration': True,
                         'target_variable': 'unsure'}
     }

b = {'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}}

c = update(a, b)

print(a, '\n')
print(b, '\n')
print(c, '\n')
输出:

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"}, 'calibration': True, 'target_variable': 'unsure'}} 

{'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}} 

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}, 'calibration': True, 'target_variable': 'unsure'}}
{
  "data_extraction": {
    "if_extraction": false,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201001'",
      "END_DT": "'201004'"
    },
    "calibration": true,
    "target_key_variable": "unsure"
  }
}


你就快到了。。。在这个实现中,我使用deepcopy来避免覆盖原始字典

def update_dict(source_dict, dict1):
    for key in source_dict:
        if key in dict1.keys():
            source_dict.update(dict1)
        elif isinstance(source_dict[key],dict):
            update_dict(source_dict[key], dict1)


source_dict = {'data_extraction': {'if_extraction': False,
      'path_data': 'data_extraction/extractions.sql',
      'set_params': {'START_DT': "'201901'",
       'END_DT': "'202104'"},
      'calibration': True,
      'target_variable': 'unsure'}}

dict1= {'set_params': {'START_DT': "'201001'",
   'END_DT': "'201004'"
}}

update_dict(source_dict, dict1)

print(source_dict)

>> 
{'data_extraction': {'if_extraction': False,
  'path_data': 'data_extraction/extractions.sql',
  'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"},
  'calibration': True,
  'target_variable': 'unsure'}}
from copy import deepcopy

def update(d, u):
    r = deepcopy(d)
    for k, v in r.items():
        if type(v) is dict:
            for _k, _v in v.items():
                if _k in u:
                    r[k][_k] = u[_k]
        elif k in u:
            r[k] = u[k]
    return r


a = {'data_extraction':{'if_extraction': False,
                         'path_data': 'data_extraction/extractions.sql',
                         'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"},
                         'calibration': True,
                         'target_variable': 'unsure'}
     }

b = {'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}}

c = update(a, b)

print(a, '\n')
print(b, '\n')
print(c, '\n')
输出:

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"}, 'calibration': True, 'target_variable': 'unsure'}} 

{'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}} 

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}, 'calibration': True, 'target_variable': 'unsure'}}
{
  "data_extraction": {
    "if_extraction": false,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201001'",
      "END_DT": "'201004'"
    },
    "calibration": true,
    "target_key_variable": "unsure"
  }
}


您需要让递归函数检查每个嵌套字典,看看它是否包含需要替换为目标_键的键。在下面的代码中,这是从传递给update函数的替换字典参数new_dict中检索的。这只需要执行一次,因此有一个嵌套的_update函数来执行实际的替换

import collections.abc

original = {
  "data_extraction": {
    "if_extraction": False,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201901'",
      "END_DT": "'202104'"
    },
    "calibration": True,
    "target_key_variable": "unsure"
  }
}

dict1 = {
  "set_params": {
    "START_DT": "'201001'",
    "END_DT": "'201004'"
  }
}


def update(d, new_dict):
    target_key, new_value = list(new_dict.items())[0]

    def nested_update(d, new_dict):
        for key, value in d.items():
            if key == target_key:
                d[key] = new_value
            elif isinstance(value, collections.abc.Mapping):
                d[key] = nested_update(value, new_dict)
        return d

    nested_update(d, new_dict)
    return d

update(original, dict1)

import json
print(json.dumps(original, indent=2))  # Pretty-print result.
输出:

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"}, 'calibration': True, 'target_variable': 'unsure'}} 

{'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}} 

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}, 'calibration': True, 'target_variable': 'unsure'}}
{
  "data_extraction": {
    "if_extraction": false,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201001'",
      "END_DT": "'201004'"
    },
    "calibration": true,
    "target_key_variable": "unsure"
  }
}


您需要让递归函数检查每个嵌套字典,看看它是否包含需要替换为目标_键的键。在下面的代码中,这是从传递给update函数的替换字典参数new_dict中检索的。这只需要执行一次,因此有一个嵌套的_update函数来执行实际的替换

import collections.abc

original = {
  "data_extraction": {
    "if_extraction": False,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201901'",
      "END_DT": "'202104'"
    },
    "calibration": True,
    "target_key_variable": "unsure"
  }
}

dict1 = {
  "set_params": {
    "START_DT": "'201001'",
    "END_DT": "'201004'"
  }
}


def update(d, new_dict):
    target_key, new_value = list(new_dict.items())[0]

    def nested_update(d, new_dict):
        for key, value in d.items():
            if key == target_key:
                d[key] = new_value
            elif isinstance(value, collections.abc.Mapping):
                d[key] = nested_update(value, new_dict)
        return d

    nested_update(d, new_dict)
    return d

update(original, dict1)

import json
print(json.dumps(original, indent=2))  # Pretty-print result.
输出:

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201901'", 'END_DT': "'202104'"}, 'calibration': True, 'target_variable': 'unsure'}} 

{'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}} 

{'data_extraction': {'if_extraction': False, 'path_data': 'data_extraction/extractions.sql', 'set_params': {'START_DT': "'201001'", 'END_DT': "'201004'"}, 'calibration': True, 'target_variable': 'unsure'}}
{
  "data_extraction": {
    "if_extraction": false,
    "path_data": "data_extraction/extractions.sql",
    "set_params": {
      "START_DT": "'201001'",
      "END_DT": "'201004'"
    },
    "calibration": true,
    "target_key_variable": "unsure"
  }
}



但是replacment dict包含存在的键,那么为什么要追加?键在子dict中重复,唯一起作用的键是用于将其添加到列表中的键。我如何升级函数以在任何位置找到它(例如嵌套或未嵌套)?要更新的数据在数据提取内部,只需在此处更新即可。原始[data_extraction][START_DT]=dict1[set_params][START_DT]但重放dict包含存在的键,为什么要追加?这些键在子dict中重复,唯一起作用的键是用于将其添加到列表中的键。我如何升级该函数以在任何位置找到它,例如嵌套或不嵌套?要更新的数据在数据提取内部,只需在那里更新即可。原始[数据提取][开始提取]=dict1[设置参数][开始提取]这起作用,但是,是否没有一种程序化的更新方式,因此我不必指定数据提取?我有点希望能够以一种不必指定键的方式来完成它。@Maths12我同意了。这就是为什么这里需要递归函数。检查我下面的答案。这是可行的,但是没有一种程序化的更新方式,所以我不必指定数据提取?我有点希望能够以一种不必指定键的方式来完成它。@Maths12我同意了。这就是为什么这里需要递归函数。检查我下面的答案。谢谢。如果我没有将源代码dict作为参数传递,那么我有:def update_dict_originaldict1:source_dict=original for key in source_dict:if key in dict1.keys:source_dict.updatedict1 elif is instancesource_dict[key],dict:update\u dict\u originaldict1返回源代码\u dict-i在代码中出现递归错误,因为它是一个递归函数source\u dict=original,所以每次函数调用都会执行。谢谢,如果我没有将source dict作为参数传递,那么我有:def update\u dict\u originaldict1:source\u dict=original for key in source\u dict:if key in dict1.keys:source\u dict.updatedict1 elifisinstancesource_dict[键],dict:更新_dict_原点
aldict1 return source_dict-i get recursion ERROR在您的代码中,因为它是一个递归函数source_dict=original,在每次函数调用中都会执行。