Python JSON 与序列化
json 模块编解码文本与 Python 基础类型;自定义对象需 default/钩子或显式 DTO。
#concept
#growing
#dev
#python
#python
[!info] related notes
Python JSON 与序列化
这个概念为什么出现
API、配置、日志事件普遍 JSON。类型映射与失败模式(非法 JSON、非 UTF-8、不可序列化对象)必须清楚。
[!abstract] 一句话理解
json.dumps生成 str;loads接受 str、bytes 或 bytearray,结果也可以是标量或 None。复杂对象需显式转换,语法解析不等于业务校验。
最小可运行示例
场景:下单 API 编解码 body
# order_json_demo.py
# 业务意图:解析下单 JSON 并回编码响应。
# 教学点:loads/dumps;类型映射;错误。
import json
def parse_order(raw: str) -> dict:
data = json.loads(raw)
if not isinstance(data, dict):
raise ValueError("order must be a JSON object")
if not isinstance(data.get("sku"), str) or not data["sku"].strip():
raise ValueError("sku must be a nonempty string")
# bool 是 int 的子类,此处要求真正的正整数。
if type(data.get("qty")) is not int or data["qty"] <= 0:
raise ValueError("qty must be a positive integer")
return data
def main() -> None:
raw = '{"sku":"SKU-1","qty":2}'
order = parse_order(raw)
print(order)
print(json.dumps({"ok": True, "order": order}, ensure_ascii=False))
try:
parse_order("{")
except json.JSONDecodeError as exc:
print("bad json:", type(exc).__name__)
if __name__ == "__main__":
main()
建议运行:
python order_json_demo.py
期望输出:
{'sku': 'SKU-1', 'qty': 2}
{"ok": true, "order": {"sku": "SKU-1", "qty": 2}}
bad json: JSONDecodeError
结合场景再看三个关注点
- 对象→dict/list/str/number/bool/null。
- datetime/自定义类需转换。
ensure_ascii=False保留非 ASCII 字符,仍返回 str;写文件/网络时另定编码。本例只检查根对象、sku 和 qty,不验证库存、权限或幂等性。
核心概念与准确模型
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number | int/float |
| true/false/null | True/False/None |
load/dump针对文件default=/object_hook
边界情况与反直觉行为
- 浮点数默认解析为 float;金额需要精确小数时可用
parse_float=Decimal,但 Decimal 再编码需显式策略。 - JSON 对象键是字符串;dumps 仅自动转换 str/int/float/bool/None 键,tuple 等键默认报 TypeError。转换可能导致键冲突,往返后也不会恢复原键类型。
- 大整数与 JavaScript 互操作时应约定安全范围或字符串表示。
- 默认编码/解析允许 NaN、Infinity 等非标准值;编码可设
allow_nan=False,解析可用拒绝常量的parse_constant。重复对象键默认保留最后一个,需拒绝时使用object_pairs_hook。
常见误区
[!warning] 常见误区:直接 dumps 任意对象 错误理解:魔法序列化一切。
正确模型:先明确 DTO/编码规则;asdict 的结果仍可能含 datetime、Decimal 等不可直接 JSON 编码的值。
工程实践
- 边界校验(pydantic 等)
- 版本化 schema
- 日志脱敏
本节总结
JSON 是跨服务契约。编解码简单,契约治理不易。
自测题
loads失败抛什么?- dataclass 怎么 JSON?
参考答案
- 非法 JSON 语法通常抛
JSONDecodeError;非法字节编码可抛UnicodeDecodeError,不支持的输入类型可抛TypeError,自定义钩子也可抛其他异常。 - 先
asdict或显式 DTO,再按字段类型转换;自定义编码器不等于自动验证 schema。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| json | 文档 | 标准库 |