
本文详解如何处理 python 中“字面量为字符串的 json 数组”这一常见反模式:当字典值实际是 json 格式字符串(而非原生数据结构)时,需用 json.loads() 显式解析,否则直接索引将操作字符而非对象。
本文详解如何处理 python 中“字面量为字符串的 json 数组”这一常见反模式:当字典值实际是 json 格式字符串(而非原生数据结构)时,需用 json.loads() 显式解析,否则直接索引将操作字符而非对象。
在实际开发中(尤其是从配置文件、API 响应或旧版序列化格式读取数据时),我们常遇到一种易被忽略的“伪结构”:表面看是嵌套数据,实则最内层是 JSON 格式的字符串。例如以下结构:
data = {
"test": ['[{"Day":"Monday","Device":"Android","Data":[1, 2, 3]}, {"Day":"Tuesday","Device":"Iphone","Data":[10, 20, 30]}]']
}乍看 data["test"] 是一个包含字典列表的列表,但执行 data["test"][0][0] 得到 '[' —— 这说明 data["test"][0] 并非列表或字典,而是一个字符串,其内容恰好是 JSON 编码后的数组文本。
✅ 正确解法:两步解析
- 提取字符串:data["test"][0] 获取 JSON 字符串;
- 反序列化:用 json.loads() 将其转为真正的 Python 列表(含字典元素)。
完整可运行示例:
import json
data = {
"test": ['[{"Day":"Monday","Device":"Android","Data":[1, 2, 3]}, {"Day":"Tuesday","Device":"Iphone","Data":[10, 20, 30]}]']
}
# Step 1: 取出字符串
json_str = data["test"][0]
# Step 2: 解析为 Python 对象(list of dicts)
parsed_list = json.loads(json_str)
# 现在可安全遍历
for item in parsed_list:
print(f"Day: {item['Day']}, Device: {item['Device']}, Data: {item['Data']}")
# 输出:
# Day: Monday, Device: Android, Data: [1, 2, 3]
# Day: Tuesday, Device: Iphone, Data: [10, 20, 30]⚠️ 关键注意事项
- 不要跳过 json.loads():直接对 json_str[0] 索引得到的是字符串首字符 '[',而非第一个字典;
-
确保 JSON 合法性:若字符串含非法转义、编码错误或不闭合括号,json.loads() 会抛出 json.JSONDecodeError,建议包裹异常处理:
try: parsed_list = json.loads(data["test"][0]) except json.JSONDecodeError as e: raise ValueError(f"Invalid JSON in data['test'][0]: {e}") - 警惕嵌套层级陷阱:本例中结构为 dict → list → str → list → dict;若来源格式不一致(如多层字符串包裹),需递归解析或校验类型;
- 性能提示:频繁解析相同字符串时,可考虑缓存结果;但切勿将 json.loads() 写入循环内部做重复解析(除非输入动态变化)。
✅ 总结
该问题本质是数据类型混淆:将 JSON 文本误认为已解析对象。Python 不会自动解析字符串内容——这是明确的设计选择(保障安全与显式性)。只要牢记“字符串 ≠ 数据结构”,并在访问前用 json.loads() 显式转换,即可稳健处理此类嵌套场景。养成检查 type(value) 的习惯(如 print(type(data['test'][0])) 输出
立即学习“Python免费学习笔记(深入)”;










