如何高效遍历Python嵌套字典?求优化多循环判断的方案
首先提个小细节:你给出的初始代码里有个笔误——v1应该是v,不然会报未定义的错误哦。接下来咱们聊聊怎么优化这段逻辑,减少嵌套循环和判断,同时让代码更易读、更灵活。
你的需求回顾
我有一个嵌套结构的Python字典,除了
values键外,还可能存在values1、values2等同类型的键。需要查找其中的random1和random2字段:若存在,则检查其下是否存在val字段。字典示例:
d = {"values": [ { "name": "A1234", "description": "A1234-Description ", "random1": { "abcd": { "val": 1 } }, "random2": { "abcd": { "val": -1 } } }, { "name": "A4567", "description": "A4567-Description ", "random1": { "abcd": { "val": 1 } }, "random2": { "abcd": { "val": -1 } } }, { "name": "B1234", "description": "B1234-Description ", } ]}初始代码(修正笔误后):
for i in d["values"]: for k, v in i.items(): if k in ("random1", "random2") and "abcd" in v: if len(v["abcd"]) != 0: if "val" in v["abcd"]: print("Found") else: print("Not found") else: print("empty")
优化方案
1. 用字典get()干掉多层嵌套if
字典的get()方法是处理嵌套结构的神器——它允许你安全地获取深层键,不存在时返回默认值(比如空字典{}),这样可以把多层if判断合并成更简洁的逻辑:
# 定义要检查的目标字段 target_keys = ("random1", "random2") # 先遍历所有类似values的键(values、values1、values2...) for list_key in [k for k in d if k.startswith("values")]: # 遍历每个列表里的条目 for item in d[list_key]: # 逐个检查目标字段 for key in target_keys: # 逐层获取,不存在就返回空字典 abcd_dict = item.get(key, {}).get("abcd") if not abcd_dict: print(f"{key} -> abcd 为空或不存在") elif "val" in abcd_dict: print(f"{key} -> 找到val: {abcd_dict['val']}") else: print(f"{key} -> abcd中没有val字段")
这种写法把原来的3层if压缩成了1层,逻辑更清晰,还避免了键不存在时的KeyError。
2. 用生成器表达式快速筛选结果
如果你不需要打印每一步,而是要收集所有符合条件的val信息,可以用生成器表达式(或者列表推导式)来简化循环,效率也更高:
from collections.abc import Iterable target_keys = ("random1", "random2") # 生成器:收集所有存在val的条目信息 valid_entries = ( (list_key, item["name"], key, abcd["val"]) # 遍历所有values开头的键 for list_key in d if list_key.startswith("values") # 遍历每个列表的条目 for item in d[list_key] # 遍历目标字段 for key in target_keys # 用海象运算符赋值并判断:abcd存在且非空,同时包含val if (abcd := item.get(key, {}).get("abcd")) and isinstance(abcd, dict) and "val" in abcd ) # 遍历结果 for entry in valid_entries: print(f"列表: {entry[0]}, 条目名称: {entry[1]}, 字段: {entry[2]}, val值: {entry[3]}")
这里用到了Python 3.8+的海象运算符:=,可以在条件判断里同时赋值,减少额外的变量声明。生成器是惰性求值的,不会一次性把所有结果加载到内存里,适合处理大字典。
3. 借助collections.ChainMap合并多列表遍历
如果你的字典里有多个values类列表(比如values、values1),想把它们合并成一个逻辑上的可迭代对象,不用创建新列表,可以用collections.ChainMap:
from collections import ChainMap target_keys = ("random1", "random2") # 把所有values开头的列表合并成一个ChainMap(不会复制数据,节省内存) all_items = ChainMap(*[d[k] for k in d if k.startswith("values")]) for item in all_items: for key in target_keys: abcd_dict = item.get(key, {}).get("abcd") if not abcd_dict: print(f"{key} -> abcd 为空或不存在") elif "val" in abcd_dict: print(f"{key} -> 找到val: {abcd_dict['val']}") else: print(f"{key} -> abcd中没有val字段")
ChainMap只是把多个列表“链接”在一起,不会生成新的列表,对内存友好,尤其是当你的列表很大的时候。
4. 封装通用工具函数复用逻辑
如果需要频繁检查嵌套字典的深层路径,可以写一个通用函数,以后直接调用就行:
def get_nested_value(data: dict, path: Iterable, default=None): """ 获取嵌套字典中指定路径的值,路径不存在则返回default :param data: 原始字典 :param path: 键的路径,比如["random1", "abcd", "val"] :param default: 路径不存在时的返回值 """ current = data for key in path: current = current.get(key, default) if current is default: break return current # 使用示例 target_keys = ("random1", "random2") for list_key in [k for k in d if k.startswith("values")]: for item in d[list_key]: for key in target_keys: val = get_nested_value(item, [key, "abcd", "val"]) if val is not None: print(f"{key} -> 找到val: {val}") else: # 可以进一步判断是哪一层出了问题 abcd = get_nested_value(item, [key, "abcd"]) if abcd is None: print(f"{key} -> abcd 不存在") elif not abcd: print(f"{key} -> abcd 为空") else: print(f"{key} -> abcd中没有val字段")
这个函数可以复用在任何嵌套字典的路径查找场景,让代码更模块化。
总结
- 优先用
dict.get()处理嵌套结构,减少KeyError和多层if; - 海象运算符
:=能在条件中赋值,简化代码; collections.ChainMap适合合并多列表遍历,节省内存;- 封装通用函数可以提升代码的可维护性和复用性。
内容的提问来源于stack exchange,提问作者Fresher

