Python json 模块的序列化边界

10次阅读

python json模块仅支持None、boolintFloat、str、list、tuple、dict(键为str)的原生序列化;set、datetime、bytes、自定义类等会报TypeError;可通过default参数、继承jsonEncoder或预处理数据结构来安全扩展。

Python json 模块的序列化边界

Python 的 json 模块不能直接序列化任意对象,它只支持有限的几种原生 Python 类型。所谓“序列化边界”,就是指哪些类型能被 json.dumps()json.dump() 安全处理,哪些会报错,以及如何在边界外安全扩展。

json 原生支持的类型(安全边界内)

以下类型可直接被 json 模块序列化,无需额外处理:

  • None → JSON NULL
  • boolTrue/False)→ JSON true/false
  • intfloat → 对应 JSON 数字(包括 inf-infnan 会被转为 null 或引发 ValueError,取决于 allow_nan 参数)
  • str → JSON 字符串(自动处理 Unicode、转义)
  • listtupledict(键必须是 str)→ JSON 数组和对象

常见不支持类型及典型错误

以下类型调用 json.dumps() 会直接抛出 TypeError

  • set:报 Object of type set is not JSON serializable
  • datetimedatetime:无法自动转字符串
  • bytesbytearray:需先解码为 str 或编码为 base64 字符串
  • 自定义类实例(如 class Person: pass):默认无 __dict__ 映射逻辑,也不触发任何转换
  • 函数模块typeellipsis (…) 等:完全不在序列化语义范围内

突破边界的常用方法

有三种主流方式在保持 json 标准兼容的前提下扩展序列化能力:

立即学习Python免费学习笔记(深入)”;

  • 使用 default 参数:传入一个 callable,当遇到不支持类型时,由它返回一个可序列化的替代值。例如:
    json.dumps(obj, default=Lambda x: x.isoformat() if isinstance(x, datetime) else str(x))
  • 继承 json.JSONEncoder:重写 default() 方法,更清晰、可复用。适合项目中统一处理日期、枚举、自定义模型等。
  • 预处理数据结构:在调用 dumps 前,用递归工具函数(如 dataclasses.asdict()pydantic.BaseModel.model_dump())将复杂对象转为 dict/list/str/int/float/None 组合。

特别注意的边界细节

有些行为看似“能过”,实则隐含风险:

  • dict 的 key 必须是 str:若传入 {1: "a", (1,2): "b"},会报错;{'1': "a", '(1, 2)': "b"} 才合法
  • 浮点精度丢失:JSON 规范不定义浮点精度,Python 默认用 repr() 级别输出,但某些极小或极大浮点数可能被科学计数法表示或截断
  • 循环引用json 模块不检测也不支持,会无限递归导致 RecursionError
  • NaN / Infinity:默认禁止(ValueError),开启 allow_nan=True 后会转为 null(非标准 JSON),部分解析器可能拒绝
text=ZqhQzanResources