直接用 json.loads() 后遍历易出错,因嵌套深、类型混杂(dict/list/None/自定义对象),硬写递归易漏 list 中 dict 或在 None 调用 .items() 报错;键名重复(如多处 "user")导致扁平后冲突;flatten_dict 库需配置 separator="_"、enumerate_types=(list,)、keep_empty_types=() 才适配真实数据;手写函数须支持 max_depth 和 skip_keys 过滤无用字段。

为什么直接用 json.loads() 后遍历会出错?
因为嵌套层级深、类型混杂(dict、list、None、甚至自定义对象),硬写递归容易漏掉 list 中的字典,或在 None 上调用 .items() 报 AttributeError。更麻烦的是键名重复——比如多个 {"user": {"id": 1}} 和 {"order": {"user": {"name": "A"}}},扁平后都可能生成 user_id,冲突不可避免。
flatten_dict 库能直接用,但要注意三个默认行为
第三方库 flatten_dict 确实省事,但它默认用 . 当分隔符、不处理 list、且把 None 变成空字符串。实际数据里常有数组字段(如 "tags": ["a", "b"])和缺失字段("phone": null),必须显式配置:
- 用
separator="_"避免点号在字段名中引发歧义(比如原始 key 是"v1.2.3") - 加
enumerate_types=(list,)才能把["x", "y"]展开成tags_0="x",tags_1="y" - 设
keep_empty_types=()防止None被转成"",保留为None更利于后续判断
手写扁平化函数时,max_depth 和 skip_keys 是刚需
真实业务 JSON 常含大段无用字段(如 "debug_info"、"raw_xml"),全展开既慢又占内存。手写时务必支持深度限制和键过滤:
def flatten_json(obj, prefix="", sep="_", max_depth=5, skip_keys=("debug_info", "meta")):
if max_depth <= 0:
return {f"{prefix}": obj} if prefix else {"_truncated": True}
if not isinstance(obj, (dict, list)):
return {prefix: obj} if prefix else {"" : obj}
result = {}
if isinstance(obj, dict):
for k, v in obj.items():
if k in skip_keys:
continue
new_key = f"{prefix}{sep}{k}" if prefix else k
result.update(flatten_json(v, new_key, sep, max_depth - 1, skip_keys))
elif isinstance(obj, list):
for i, item in enumerate(obj):
new_key = f"{prefix}{sep}{i}" if prefix else str(i)
result.update(flatten_json(item, new_key, sep, max_depth - 1, skip_keys))
return result注意:这里 skip_keys 是元组而非列表,避免被误修改;max_depth 从外向内递减,到 0 就截断并打标记,比单纯抛异常更可控。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
立即学习“Python免费学习笔记(深入)”;
扁平后字段爆炸?用 pandas.json_normalize 做定向提取
当只关心某几层(比如所有 user.name 和 order.items[].price),不用全量扁平。用 pandas.json_normalize 指定 record_path 和 meta 更高效:
import pandas as pd
df = pd.json_normalize(
data,
record_path=["orders", "items"], # 提取嵌套数组
meta=[["user", "id"], ["user", "name"], ["order_id"]], # 提取父级字段
errors="ignore"
)关键点:errors="ignore" 防止某条记录缺 user 字段就整个失败;meta 中用列表表示嵌套路径,比手拼 key 安全;返回是 DataFrame,天然支持去重、筛选、导出,比纯字典更适合后续分析。
复杂嵌套里最易忽略的不是怎么展,而是“展到哪”——没约束的扁平化等于制造新混乱。字段命名冲突、list 处理方式、空值表示、性能边界,每个都得在动手前想清楚。

















