← 中文资源

简体中文版本

Python TypeError — 对象无法 JSON 序列化

通过提供 default 处理器,或在 dump 前转换日期、集合与自定义对象,修复 “Object of type X is not JSON serializable”。

阅读英文原文

症状

错误“Python TypeError — 对象无法 JSON 序列化”指向一个明确的失效模式。下面依次给出症状、定位该原因的检查命令、根本原因、修复方案,以及证明修复有效的验证步骤。

可观察到的症状包括:

  • TypeError: Object of type datetime is not JSON serializable
  • json.dumps 正常,直到响应含有日期或集合
  • Web 框架在序列化模型对象时返回 500

诊断

先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。

步骤 1

python -c "import json, datetime; json.dumps({'t': datetime.datetime.now()})"

错误会点明确切类型,据此可确定需要哪种转换。

步骤 2

json.dumps(obj, default=lambda o: o.isoformat() if hasattr(o,'isoformat') else str(o))

default 处理器可转换未知类型;ISO 格式日期是常见选择。

常见诱因(按出现频率排序):

  • 值中含默认编码器不理解的 datetime、set、Decimal、UUID 或 bytes
  • 传入的是 ORM 或类实例,而非纯 dict/list
  • 自定义类在边界处缺少 to_dict 或 ISO 转换

根因

标准 JSON 编码器仅支持 dict、list、str、int、float、bool 与 None。其他类型在编码时都要抛 TypeError,除非用 default 可调用或自定义编码器转换。

修复

在边界处转换:日期格式化为 ISO 字符串,set/Decimal 转为 list/float,UUID 转 str,ORM 模型转 dict。提供统一的 default 处理器以保证一致。

注意:用 str() 兜底可能泄露意外表示;更好的是按类型显式转换,而非一律 str。

import json
from datetime import date, datetime
from decimal import Decimal
from uuid import UUID

def default_handler(o):
    if isinstance(o, (datetime, date)):
        return o.isoformat()
    if isinstance(o, (set, frozenset)):
        return sorted(o)
    if isinstance(o, (Decimal, UUID)):
        return str(o)
    raise TypeError(f'not serializable: {type(o).__name__}')

payload = {'id': UUID(int=0), 'at': datetime.now(), 'tags': {'a', 'b'}}
print(json.dumps(payload, default=default_handler))

验证

重新 dump 并确认 JSON 合法;解析回来并断言日期以 ISO 字符串往返。为每种自定义类型补充测试。

修复后补充一条回归测试,复现原始症状,防止问题再次出现。

这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。