Python优雅地dumps非标准类型
專 欄
❈正小歪,Python 工程师,主要负责 Web 开发和日志数据处理。博客文章《真正的 Tornado 异步非阻塞》、《使用 JWT 让你的 RESTful API 更安全》等多次入选知名技术社区每日精选。《使用 Shipyard 搭建 Docker 集群》被选入 Dockerone 周报。
个人博客: https://www.hexiangyu.me
GitHub: https://github.com/zhengxiaowai❈
在用Python编程时很经常做的一件事就是 Python 数据类型和 JSON 数据类型的转换。
但是存在一个明显的问题,JSON 作为一种数据交换格式有固定的数据类型,但是 Python 作为编程语言除了内置的数据类型以外还能编写自定义的数据类型。
墙裂推荐:去看看 JSON 官网对 JSON 的介绍:http://www.json.org/json-zh.html
比如你肯定遇到过类似的问题:
那么问题就来了,如何把各种各样的 Python 数据类型转化成 JSON 数据类型。 一种很不 pythonic 的做法就是,先转换成某种能和 JSON 数据类型直接转换的值,然后在 dump,这么做很直接很暴力,但是在各种花式数据类型面前就很无力。
Google 是解决问题的重要方式之一,当你一顿搜索过后,你就会发现其实可以在 dumps 时 encode 这个阶段对数据进行转化。
所以你肯定是那么做的,完美地解决了问题。
JSON 的 Encode 过程
文中代码摘自 https://github.com/python/cpython 删除了几乎所有的 docstring,由于代码太长,直接截取了重要片段。可以在片段最上方的链接查看完整的代码。
熟悉 json 这个库的都知道基本只有4个常用的 API,分别是 dump、dumps 和 load、loads。
源码位于 cpython/Lib/json 中
直接看到最后的 return。可以发现如果不提供 cls 默认就使用 JSONEncoder,然后调用该类的实例方法 encode。
encode 方法也十分简单:
可以看出最后的我们得到 JSON 都是 chunks 拼接得到的,chunks 是调用 self.iterencode 方法得到的。
iterencode 方法比较长,我们只关心最后几行。
返回值 _iterencode
,是函数中 c_make_encoder
或者 _make_iterencode
这两个高阶函数的返回值。
c_make_encoder
是来自 _json
这个 module ,这个 module 是一个 c 模块,我们不去关心这个模块怎么实现的。
转去研究同等作用的 _make_iterencode
方法。
同样需要关心的只有返回的这个函数,代码里各种 if-elif-else 逐一把内置类型转换成 JSON 类型。
在对面无法识别的类型时候就使用了 _default()
这个方法,然后递归调用解析各个值。
_default
就是最前面那个被覆盖的 default
。
到这里就可以完全了解 Python 是如何 encode 成 JSON 数据。
总结一下流程,json.dumps()
调用 JSONEncoder 的实例方法 encode()
,随后使用 iterencode()
递归转化各种类型,最后把 chunks 拼接成字符串后返回。
优雅的解决方案
通过前面的流程分析之后,知道为什么继承 JSONEncoder 然后覆盖 default 方法就可以完成自定义类型解析了。
也许你以后需要解析 datetime 类型数据,你可定会那么做:
最后调用父类是 default()
方法纯粹是为了触发异常。
Python 可以使用 singledispatch 来解决这种单泛型问题。
这种写法比较符合设计模式的规范。假如以后有了新的类型,不用再修改ExtendJSONEncoder
类,只需要添加适当的 singledispatch 方法就可以了, 比较 pythonic 。
如果你执意的想在类中添加 singledispatch 可以参考:https://stackoverflow.com/a/24602374/5227020 ,当然我仍然觉得还是不要写在类中比较好。
- 印度6大科技真相 会让很多人大吃一惊
- 了解ASP.NET MVC几种ActionResult的本质:HttpStatusCodeResult & RedirectResult/RedirectToRouteResult
- Python原创0基础入门一看几张图就学会了
- ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】
- 了解ASP.NET MVC几种ActionResult的本质:FileResult
- ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求
- 如何用Python和深度神经网络识别图像?
- 余军:分布式数据库在金融行业的创新实践
- 微信小游戏采用了我们都忽略的产品推广新切入点
- ASP.NET MVC下的四种验证编程方式[续篇]
- 如何把业务问题变成机器学习的问题?
- 这算是ASP.NET MVC的一个大BUG吗?
- 【Scikit-Learn 中文文档】分解成分中的信号(矩阵分解问题) - 无监督学习 - 用户指南 | ApacheCN
- 区块链技术在非能源领域的应用场景
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spring 的 Controller 是单例还是多例?怎么保证并发的安全
- Python游戏开发 制作AI贪吃蛇!
- Python老司机手把手带你写爬虫,整站下载妹子图,一次爽个够!
- 教你用云开发打造一个双端自动发布的博客体系(下)
- 国科大&中科院提出CANet:用于图像复原的拼接注意力网络
- 【Kubernetes】Octant部署
- 使用注意力机制来做医学图像分割的解释和Pytorch实现
- 用Python写个爬虫小程序,给女朋友每日定时推送睡前小故事
- 数据量大的表建立索引或者修改表结构太慢的解决办法
- Activiti7入门Demo
- mybatis 中#与$的区别
- Spring中的FactoryBean和BeanFactory
- MybatisPlus分页插件无效解决方案
- springboot+mybatis打印sql
- jquery插件与扩展