如何使用递归方法更新python字典

Posted

技术标签:

【中文标题】如何使用递归方法更新python字典【英文标题】:How to use recursive method to update python dictionaries 【发布时间】:2021-12-30 23:58:08 【问题描述】:

我正在使用 Python zeep 发出 SOAP 请求。据我所知,zeep 可以使用字典作为输入来提出请求。

由于我正在使用多种方法,因此我想创建一个通用函数来接收参数及其在方法的 WSDL 中定义的相应层次结构,并构造 request_data_dictionary,考虑到它可能包含嵌套数据,它可能非常复杂。

在定义我的参数时,我给了他们一个级别属性,以了解该参数在请求数据字典中的深度。而且我确信参数是按顺序处理的。

我的测试用例具有以下结构。我有 4 个参数:par1、par2、par3 和 par4。每个参数都是编号较小的参数的子参数,因此 par2 是 par1 的子参数,依此类推。我需要的数据输出形式如下:

'par0': 'par1': 'par2': 'par3': 'par4': False

如果我添加一个 par2.1 作为 par1 的另一个孩子,字典应该有这种形式:

'par0': 'par1': 'par2.1': False, 'par2': 'par3': 'par4': False

所以我编写了以下函数来构造我的 request_dictionary:

    def _prepare_request_dictionary(self):
        data_dictionary = 
        for line in self.request_line_ids.sorted(key=lambda l: l.parameter_id.level):
            parameter_name = line.parameter_id.name
            parent_parameter_name = line.parameter_id.parent_id.name if line.parameter_id.parent_id else False
            line_value = convert_value(line.value, line.parameter_type) if not line.parameter_id.is_compound and line.value else False
            if line.parameter_id.level == 1 and parameter_name not in data_dictionary.keys():
                data_dictionary[parameter_name] = line_value
            elif line.parameter_id.level == 2:
                if parent_parameter_name in data_dictionary.keys():
                    data_dictionary = if isinstance(data_dictionary[parent_parameter_name], dict):
                        data_dictionary[parent_parameter_name] = **data_dictionary[parent_parameter_name], **parameter_name: line_value
                    elif isinstance(data_dictionary[parent_parameter_name], list):
                        data_dictionary[parent_parameter_name].append(parameter_name: line_value)
                    elif data_dictionary[parent_parameter_name] is False:
                        data_dictionary[parent_parameter_name] = parameter_name: line_value
            elif line.parameter_id.level == 3:
                for value in data_dictionary.values():
                    if isinstance(value, dict):
                        if parent_parameter_name in value.keys():
                            if isinstance(value[parent_parameter_name], dict):
                                value[parent_parameter_name] = **value[parent_parameter_name], **parameter_name: line_value
                            elif isinstance(value[parent_parameter_name], list):
                                value[parent_parameter_name].append(parameter_name: line_value)
                            elif value[parent_parameter_name] is False:
                                value[parent_parameter_name] = parameter_name: line_value
            elif line.parameter_id.level == 4:
                for value in data_dictionary.values():
                    if isinstance(value, dict):
                        for sub_value in value.values():
                            if parent_parameter_name in sub_value.keys():
                                if isinstance(sub_value[parent_parameter_name], dict):
                                    sub_value[parent_parameter_name] = **sub_value[parent_parameter_name], **parameter_name: line_value
                                elif isinstance(sub_value[parent_parameter_name], list):
                                    sub_value[parent_parameter_name].append(parameter_name: line_value)
                                elif sub_value[parent_parameter_name] is False:
                                    sub_value[parent_parameter_name] = parameter_name: line_value
            elif line.parameter_id.level == 5:
                for value in data_dictionary.values():
                    if isinstance(value, dict):
                        for sub_value in value.values():
                            if isinstance(sub_value, dict):
                                for sub_sub_value in sub_value.values():
                                    if isinstance(sub_sub_value, dict):
                                        if parent_parameter_name in sub_sub_value.keys():
                                            if isinstance(sub_sub_value[parent_parameter_name], dict):
                                                sub_sub_value[parent_parameter_name] = **sub_sub_value[parent_parameter_name], **parameter_name: line_value
                                            elif isinstance(sub_sub_value[parent_parameter_name], list):
                                                sub_sub_value[parent_parameter_name].append(parameter_name: line_value)
                                            elif sub_sub_value[parent_parameter_name] is False:
                                                sub_sub_value[parent_parameter_name] = parameter_name: line_value
        return data_dictionary

如你所见,这个函数有一些重复的部分,如下所示:

if isinstance(value[parent_parameter_name], dict):
                                value[parent_parameter_name] = **value[parent_parameter_name], **parameter_name: line_value
elif isinstance(value[parent_parameter_name], list):
                                value[parent_parameter_name].append(parameter_name: line_value)
elif value[parent_parameter_name] is False:
                                value[parent_parameter_name] = parameter_name: line_value

还有这个:

for value in data_dictionary.values():
   if isinstance(value, dict):
      for sub_value in value.values():
         if isinstance(sub_value, dict):
            for sub_sub_value in sub_value.values():
               if isinstance(sub_sub_value, dict):

所以我做了一个名为“update_data_dictionary”的子函数来模块化它:

def update_data_dictionary(work_dictionary, update_dictionary, parent_parameter):
    if isinstance(work_dictionary[parent_parameter], dict):
        work_dictionary[parent_parameter] = **work_dictionary[parent_parameter], **update_dictionary
    elif isinstance(work_dictionary[parent_parameter], list):
        work_dictionary[parent_parameter].append(update_dictionary)
    elif work_dictionary[parent_parameter] is False:
        work_dictionary[parent_parameter] = update_dictionary
    return work_dictionary

问题是我不知道如何在第 3 级再次使用此方法,因为函数“update_data_dictionary”返回一个无法替换值的字典。

我知道这可以通过递归函数来解决,如果有人可以帮助我将这个递归函数变成一个无限级别的递归函数,我将不胜感激。

【问题讨论】:

你能给出一个数据例子和一个你想要构建的具有理想结构的字典的例子吗?目前很难理解你的代码做了什么以及你想要实现什么。 嗨,我编辑以更好地解释我想要的字典应该如何输出。我没有提到的是我正在使用 Odoo 并且 request_line_ids 变量是我使用参数创建的模型的记录集。 【参考方案1】:

我花了一些时间,但我能够创建我需要的递归方法,它具有以下形式:

def update_data_dictionary(work_dictionary, line_value, parameter, work_level=0, sub_dictionary=None):
    parameter_name = parameter.name
    parent_parameter = parameter.parent_id.name
    parent_level = parameter.parent_id.level
    level = 1 if work_level == 0 else work_level
    update_dictionary = sub_dictionary if sub_dictionary else parameter_name: line_value
    if parent_level == level:
        if parent_parameter in work_dictionary.keys():
            if isinstance(work_dictionary[parent_parameter], dict):
                work_dictionary[parent_parameter] = **work_dictionary[parent_parameter], **update_dictionary
            elif work_dictionary[parent_parameter] is False:
                work_dictionary[parent_parameter] = update_dictionary
    else:
        for value in work_dictionary.copy().values():
            if isinstance(value, dict):
                processed_dictionary = update_data_dictionary(value, line_value, parameter, (level+1), update_dictionary)
    return work_dictionary

此方法更新任何级别中的任何子参数的内容,只要参数的级别及其父级层次结构定义良好。

【讨论】:

以上是关于如何使用递归方法更新python字典的主要内容,如果未能解决你的问题,请参考以下文章

Python:如何递归地从 NESTED 数据结构(列表和字典)中删除 None 值?

递归地将python对象图转换为字典

Python递归集合值排列字典

python合并两个字典的内容,使用update方法

python之dict与set

如何在Python中创建一个递归函数来创建一个映射Odoo 8关系字段记录的字典?