
本文介绍一种通用递归方法,将任意深度嵌套的 json 对象(含字典、列表)展平为扁平化字典,键名按路径拼接并以下划线分隔,适用于后续转为 pandas dataframe 或结构化存储。
本文介绍一种通用递归方法,将任意深度嵌套的 json 对象(含字典、列表)展平为扁平化字典,键名按路径拼接并以下划线分隔,适用于后续转为 pandas dataframe 或结构化存储。
在处理真实世界 JSON 数据时,嵌套结构(如 device.model、data[0].label)极为常见,而 pd.json_normalize() 默认行为对多层嵌套或混合类型(字典+列表)支持有限。若目标是生成类似 appVersion, device_model, data_1_timestamp 这样语义清晰、可直接映射为列名的扁平键,需自定义递归展平逻辑。
以下是一个健壮、可扩展的 flatten_dict 函数,支持三种核心类型:
- 标量值(str/int/float/None 等):直接写入 pre + key 键;
- 字典(dict):递归调用,前缀更新为 f'{pre}{key}_';
- 列表(list):遍历每个元素;若元素为字典,则递归展平并加入序号(如 data_1_timestamp);若为标量,则生成 key_1, key_2 形式键名。
import json
import pandas as pd
def flatten_dict(d: dict, pre: str = '') -> dict:
"""
递归展平嵌套字典和列表,生成扁平化键值对。
键名格式:parent_child_grandchild,列表项自动编号(从1开始)。
"""
result = {}
for key, value in d.items():
new_pre = f'{pre}{key}_'
if isinstance(value, dict):
result.update(flatten_dict(value, new_pre))
elif isinstance(value, list):
for idx, item in enumerate(value, start=1):
if isinstance(item, dict):
result.update(flatten_dict(item, f'{new_pre}{idx}_'))
else:
result[f'{new_pre}{idx}'] = item
else:
result[f'{pre}{key}'] = value
return result
# 示例数据
json_data = '''
{
"appVersion": "0.0.3",
"device": {
"model": "Lenovo"
},
"bef": {
"catalog": "Manual"
},
"data": [
{
"timestamp": "2024-04-24 12:08:02.415077",
"label": "zuf",
"category": "50"
}
]
}
'''
parsed_json = json.loads(json_data)
flattened = flatten_dict(parsed_json)
# 转为单行 DataFrame
df = pd.DataFrame([flattened])
print(df)输出结果:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
appVersion device_model bef_catalog data_1_timestamp data_1_label data_1_category 0 0.0.3 Lenovo Manual 2024-04-24 12:08:02.415077 zuf 50
✅ 关键优势说明:
- ✅ 支持无限嵌套层级(递归实现);
- ✅ 正确处理列表中的多个对象(如 data 含多条记录时,自动生成 data_1_*, data_2_*);
- ✅ 前缀命名语义明确,避免键名冲突(如 device.model 和 data.device.model 不会混淆);
- ✅ 无需依赖外部库,纯 Python 实现,兼容性高。
⚠️ 注意事项:
- 若列表中存在非字典非标量类型(如嵌套列表),需按需扩展 elif isinstance(item, list) 分支;
- 序号从 1 开始(符合自然语言习惯),如需从 0 开始,将 enumerate(..., start=1) 改为 start=0;
- 对于超大 JSON,可考虑添加递归深度限制(max_depth 参数)防止栈溢出;
- 如需保留原始数组结构(如 data 展开为多行而非单行多列),应先 pd.json_normalize(parsed_json, record_path='data', meta=['appVersion', 'device.model', ...]),再结合 flatten_dict 处理元数据。
此方法兼顾灵活性与可读性,是构建数据管道、ETL 流程或 API 响应解析器的理想基础工具。

















