Python JSON 序列化的边界与坑点

发布时间 - 2026-01-31 00:00:00    点击率:
datetime等类型需用default参数处理,NaN/Infinity需allow_nan=False校验,中文需ensure_ascii=False,自定义类应实现to_dict方法。

datetime 对象直接 json.dumps 会报错

Python 的 json.dumps 默认不支持 datetimedatebytes 等类型,遇到就抛 TypeError: Object of type datetime is not JSON serializable

常见场景是数据库查询结果含时间字段,或日志结构里带 datetime.now(),一序列化就崩。

  • 最轻量解法:用 default 参数传处理函数,比如 lambda obj: obj.isoformat() if isinstance(obj, (datetime, date)) els

    e None
  • 注意 default 函数必须覆盖所有非标类型,否则仍报错;返回 None 会导致字段消失,不是万能兜底
  • datetime 带时区(tzinfo)时,isoformat() 输出含 +08:00,但某些老系统只认 UTC 或无时区格式,得手动转成 obj.astimezone(timezone.utc).isoformat()

NaN、Infinity 在 JSON 中非法但 Python 允许 float 表示

JSON 规范明确禁止 NaNInfinity-Infinity,但 Python 的 float 可以表示它们,json.dumps 默认会静默转成 null(不报错!),极易埋雷。

典型触发点:NumPy 计算结果、pandas DataFrame 含空值运算、除零后未检查。

  • allow_nan=False 强制报错:json.dumps(data, allow_nan=False),这样能早暴露问题
  • 如果必须保留语义,可预处理:遍历结构,把 math.isnan(x)math.isinf(x) 的值替换成字符串 "NaN"null,再序列化
  • 注意 allow_nan 是开关,不是转换器——设为 False 才真正校验,设为 True(默认)反而放行非法值

中文字符被 \uXXXX 转义,前端显示乱码

默认情况下 json.dumps 会对非 ASCII 字符做 Unicode 转义,比如 "你好" 变成 "\u4f60\u597d",虽然合法,但可读性差,某些调试工具或旧版浏览器解析异常。

这不是 bug,是默认行为,源于早期对传输安全的保守设计。

  • 加参数 ensure_ascii=False 即可输出原生中文:json.dumps(data, ensure_ascii=False)
  • 但要注意 HTTP 响应头必须声明 Content-Type: application/json; charset=utf-8,否则前端可能按 latin-1 解码
  • 若数据要写入文件,推荐显式指定编码:with open("out.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False)

自定义类实例无法直接序列化

定义了 class User: 并创建实例后,直接 json.dumps(user) 会报 TypeError: Object of type User is not JSON serializable,哪怕它只有几个普通属性。

原因在于 json 模块不认识你的类,也不自动调用 __dict__——它只认内置类型和你显式告诉它的规则。

  • 简单对象可用 default=lambda o: o.__dict__,但仅限于纯数据类,且不能有循环引用、不可序列化属性(如文件句柄)
  • 更稳的方式是让类实现 to_dict() 方法,再在 default 中调用:default=lambda o: o.to_dict() if hasattr(o, "to_dict") else None
  • 别依赖 vars()__dict__ 处理带 property、动态属性或私有字段的类,容易漏字段或暴露不该导出的内容

真正难的不是怎么序列化,而是怎么确保反序列化后还能还原语义——比如时间精度丢没丢、浮点误差有没有放大、空值是 null 还是 "null" 字符串。这些边界一旦跨过,debug 成本远高于加几行 default 函数。


# python  # js  # 前端  # json  # 编码  # 浏览器  # app  # 工具  # numpy  # pandas  # Float  # Object  # NULL  # if  # date  # math  # 字符串  # 循环  # Lambda  # class  # Property  # 对象  # default  # ASCII  # 数据库  # http  # bug  # 序列化  # 报错  # 设为  # 自定义  # 会报  # 转成  # 只认  # 也不  # 浮点  # 句柄 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 制作企业网站建设方案,怎样建设一个公司网站?  如何在建站宝盒中设置产品搜索功能?  Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  Android Socket接口实现即时通讯实例代码  如何在IIS中新建站点并解决端口绑定冲突?  香港服务器租用费用高吗?如何避免常见误区?  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  Python企业级消息系统教程_KafkaRabbitMQ高并发应用  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  Thinkphp 中 distinct 的用法解析  Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理  如何挑选高效建站主机与优质域名?  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  重庆市网站制作公司,重庆招聘网站哪个好?  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  再谈Python中的字符串与字符编码(推荐)  html文件怎么打开证书错误_https协议的html打开提示不安全【指南】  Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明  如何撰写建站申请书?关键要点有哪些?  Laravel storage目录权限问题_Laravel文件写入权限设置  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  如何用AWS免费套餐快速搭建高效网站?  如何在七牛云存储上搭建网站并设置自定义域名?  微信公众帐号开发教程之图文消息全攻略  Laravel如何实现用户密码重置功能?(完整流程代码)  bing浏览器学术搜索入口_bing学术文献检索地址  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  如何基于云服务器快速搭建个人网站?  黑客如何通过漏洞一步步攻陷网站服务器?  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  php485函数参数是什么意思_php485各参数详细说明【介绍】  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  C++用Dijkstra(迪杰斯特拉)算法求最短路径  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  如何快速搭建高效可靠的建站解决方案?  海南网站制作公司有哪些,海口网是哪家的?  html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】  长沙做网站要多少钱,长沙国安网络怎么样?  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  如何快速生成可下载的建站源码工具?  *服务器网站为何频现安全漏洞?  标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析  佛山企业网站制作公司有哪些,沟通100网上服务官网?  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  进行网站优化必须要坚持的四大原则  nginx修改上传文件大小限制的方法