专栏首页Python中文社区Python优雅地dumps非标准类型

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 ,当然我仍然觉得还是不要写在类中比较好。

本文分享自微信公众号 - Python中文社区(python-china),作者:正小歪

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用 Python 分析《红楼梦》(全)

    專 欄 ❈楼宇,Python中文社区专栏作者。一位正在海外苦苦求学的本科生。初中时自学编程,后来又在几位良师的帮助下走上了计算机科学的道路。曾经的 OIer...

    Python中文社区
  • 我是如何零基础开始能写爬虫的

    利用这些数据,可以做很多领域的分析、市场调研,获得很多有价值的信息,可以应用在很多的工作场景,于是果断开始学习。

    Python中文社区
  • 不踩坑的Python爬虫:如何在一个月内学会爬取大规模数据

    Python爬虫为什么受欢迎 如果你仔细观察,就不难发现,懂爬虫、学习爬虫的人越来越多,一方面,互联网可以获取的数据越来越多,另一方面,像 Python这样的...

    Python中文社区
  • 外媒盘点2017年七大技术:将GIF动画嵌入活细菌体内

    2017年即将成为过去,最新款的苹果iPhone已经发布,美国科技媒体TNW的作者已经被机器人取代。现在是时候回顾下2017年了,我们会在假期里安顿下来,温暖舒...

    企鹅号小编
  • ABAP内表数据和JSON格式互转

    注:json字符串格式如:jsonstr = '[ {flag: "0",message: "abc"},{flag: "1",message: "abcddd...

    matinal
  • Python通过JSON-RPC请求对以太坊智能合约进行部署和交易

    本文探讨了如何将JSON-RPC请求发送到Geth节点以创建原生的交易。目标是在使用高级库(如web3py或web3js)时了解并查看后台发生的情况。

    笔阁
  • 正则表达式口诀

    正则其实也势利,削尖头来把钱揣;(指开始符号^和结尾符号$) 特殊符号认不了,弄个倒杠来引路;(指\.\*等特殊符号) 倒杠后面跟小w,数字字母来表示;(\w跟...

    DevinGeng
  • 微信小程序使用字体图标的方法

    一、先到阿里巴巴矢量图标库(http://iconfont.cn/),用微博帐号登录,搜索你想要的图标,然后添加入库 image.png 从项目里下载下来并解压...

    李文杨
  • [周末课程]什么是“页面业务流程”分析思维导图?如何编写页面假JSON数据? &下一个前端组件“日历”

    大家好,时间飞快一晃又到了周末了,今天要跟大家一起学习的有以下这些内容: -- 什么是“页面业务流程”分析思维导图?如何编写页面假JSON数据? -- 进入下一...

    web前端教室
  • One order popup window 显示逻辑

    版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)

    Jerry Wang

扫码关注云+社区

领取腾讯云代金券