Python中的嵌套字典遍历

1 投票
2 回答
665 浏览
提问于 2025-04-18 12:03

我有一个字典,这个字典里面有一些选项的键值对,还有一个叫做sub_dict的属性,这个属性是一个包含更多字典的列表,这些字典也有相同的属性,并且它们也可能有自己的sub_dict,一直往下嵌套。

在Python中,我把这些字典拆开,逐个处理,修改它们,然后想把修改后的部分重新组合回整个字典里。不过,我不太确定该怎么遍历这些字典。

{base_system: {
name: "root",
description: "data dictionary",
common_data: {},
other_data: {},
more_data: {},
sub_systems: [
    {
        base_system: {
        name: "another system",
        description: "inherits from top level",
        sub_systems: [
            {
                base_system: {}
            },
            {
                base_system: {}
            }
        ]
        }
    },
    {
        base_system: {
            name: "one more system",
            description: "inheriting again",
            sub_systems: [
            {
                base_system: {
                name: "child system",
                description: "no kids here",
                other_data: {},
                more_data: {}
                }
            },
            {
                base_system: {
                name: "kid system",
                description: "no children here"
                }
            }
            ]
        }
    }
]
}

}

我想做类似的事情,但不太确定怎么让它变成递归的。

#Have some recursive function to dig through the overall dictionary then test:
if the_dict_object["space_system"]["name"] == changed_json_system["space_system"]["name"]:
  #then when it passes that if statement I can just set
  the_dict_object = changed_json_system

不过,我不太清楚怎么遍历这个嵌套的字典,同时又能保持对整体对象的控制。

2 个回答

1

这里有一段示例代码,它会递归地遍历你的字典结构。在这个例子中,它把描述内容替换成大写形式。

_DESC = "description"
_BASESYS = "base_system"
_SUBSYS = "sub_systems"

def uppercase_desc(system_info):
    """
    Change a system object such that the description is in upper-case.
    """
    if _BASESYS not in system_info:
        return

    subd = system_info[_BASESYS]
    if _DESC in subd:
        subd[_DESC] = subd[_DESC].upper()
    if _SUBSYS not in subd:
        return
    for d in subd[_SUBSYS]:
        uppercase_desc(d)

if __name__ == "__main__":
    import json
    with open("data.json", "rt") as f:
        s = f.read()
    system_info = json.loads(s)

    uppercase_desc(system_info)
    s = json.dumps(system_info, indent=4, sort_keys=True)
    print(s)

上面的代码是在原字典上直接修改的。虽然稍微复杂一点,但其实也不难,你可以在遍历的过程中做一个副本,然后返回这个副本。这样做可能更好。

这里唯一需要注意的地方是,代码默认使用了 copy.deepcopy()。因为我们不知道字典里可能有什么内容,而且我们想返回一个副本,所以可以对所有内容调用 copy.deepcopy();这样做简单有效,对于像 3(值为3的整数)这样的简单对象也能正常工作。

import copy

_DESC = "description"
_BASESYS = "base_system"
_SUBSYS = "sub_systems"

def uppercase_desc(system_info):
    """
    Change a system object such that the description is in upper-case.
    """
    if _BASESYS not in system_info:
        raise ValueError("only works on a system info dict")

    # put in the base_system key and an empty subdir
    newsubd = {}
    new_system_info = {_BASESYS: newsubd}

    subd = system_info[_BASESYS]
    for key, value in subd.items():
        if _DESC == key:
            newsubd[key] = value.upper()
        elif _SUBSYS == key:
            newsubd[key] = [uppercase_desc(d) for d in value]
        else:
            newsubd[key] = copy.deepcopy(value)
    return new_system_info

if __name__ == "__main__":
    import json
    with open("data.json", "rt") as f:
        s = f.read()
    system_info = json.loads(s)

    new_system_info = uppercase_desc(system_info)
    s = json.dumps(new_system_info, indent=4, sort_keys=True)
    print(s)

附言:你发布的示例数据不是有效的JSON格式。我把它修改了一下,为键加上了双引号,并进行了格式化,使得我的测试文件 data.json 看起来更整齐。这里是修改后的内容:

{
    "base_system": {
        "name": "root", 
        "description": "data dictionary", 
        "more_data": {}, 
        "common_data": {}, 
        "sub_systems": [
            {
                "base_system": {
                    "name": "another system", 
                    "sub_systems": [
                        {
                            "base_system": {}
                        }, 
                        {
                            "base_system": {}
                        }
                    ], 
                    "description": "inherits from top level"
                }
            }, 
            {
                "base_system": {
                    "name": "one more system", 
                    "sub_systems": [
                        {
                            "base_system": {
                                "more_data": {}, 
                                "other_data": {}, 
                                "name": "child system", 
                                "description": "no kids here"
                            }
                        }, 
                        {
                            "base_system": {
                                "name": "kid system", 
                                "description": "no children here"
                            }
                        }
                    ], 
                    "description": "inheriting again"
                }
            }
        ], 
        "other_data": {}
    }
}
1

你可以使用 instanceof() 方法来检查某个东西是不是字典。如果是的话,你就可以让你的代码去遍历这个字典。我会在这种情况下使用递归。

def read_dict(some_dictionary):
    for key, value in some_dictionary:

        if isinstance(value, dict): 
            # if value is another dict, iterate through the key,value pairs in value
            read_dict(value) 
        elif isinstance(value, list):
            # if value is a list, add your own code to iterate through a list
            pass
        else:
            #not a dict, do what you needed to do eg:
            print 'value of %s is %s' % (key, value) 

read_dict(the_dict_object)

撰写回答