Python 与 JSON 共舞
简介
在 Python 开发中,尤其是在涉及 web 开发时,不可避免会与 JSON (JavaScript Object Notation) 打交道。本文主要尝试介绍如何在 Python 中使用 JSON 。
在 Python 3 的官方文档中关于 JSON 操作的函数主要有 4 个,它们分别是 json.dump() 、 json.load() 、 json.dumps() 和json.loads() 。 json.dump() 和 json.dumps() 的功能是将 Python 对象进行编码( encoder ) ,转化为 JSON 格式;而 json.load() 和 json.loads() 则反之,对 JSON 格式对象解码( decoder ),转化为 Python 对象。
json.dump() 与 json.dumps() 的区别
json.dump() 与 json.dumps() 的作用都是把 Python 对象序列化为 JSON 格式,不同之处在哪里呢?先来看一下两者的定义:
1 | json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) |
两者的定义基本相同,但是 json.dump() 多了一个 fp 参数。它们的主要区别是: json.dumps() 把 Python 对象序列化为一个 JSON 格式的字符串,而 json.dump() 则是把 Python 对象序列化为一个 JSON 格式的流,这个流可以直接写入到文件或者类似文件的对象。
听起来可能有一些拗口,下面来看个例子:
1 | >>> import json |
从上例中可以看出, json.dumps() 返回了一个 JSON 格式的字符串。
1 | >>> from pathlib import Path |
上例中的代码生成一个名为 /tmp/person.txt 的文件,其内容为: {"name": "dormouse", "age": 40} 。
json.load() 与 json.loads() 的区别与之类似。
编码
把 Python 对象序列化为 JSON 格式对象称为编码,主要使用 json.dump() 和 json.dumps() 函数。根据前文所述,这两个函数基本相同,下面主要以 json.dumps() 函数为例,json.dump() 函数的用法基本类似。
json.dumps() 用法示例:
1 | >>> import json |
编码数据类型对应规则如下表:
| Python | JSON |
|---|---|
| dict | object |
| list, tuple | array |
| str | string |
| int, float, int- & float-derived Enums | number |
| True | true |
| False | false |
| None | null |
常用参数
json.dumps() 和 json.dump() 可以使用许多参数,下面介绍几个常用的参数:
ensure_ascii 参数
该参数如默认值是 True ,在编码时,非 ASCII 字符会被转义,例如在上文的例子中,“其他”两个字被编码为 \\u5176\\u4ed6 。如果该参数设置为 Fasle ,
那么就不会转义。例如:
1 | >>> json.dumps(person, ensure_ascii=False) |
indent 参数
该参数控制编码结果的缩进,默认值是 None 。默认情况下会编码结果会紧缩在一起。如果该参数设置为一个正整数或者 \t ,那么会使编码结果具有更好的可读性。
例如:
1 | >>> print(json.dumps(person, ensure_ascii=False, indent=4)) |
sort_keys 参数
该参数控制编码结果是否按键值排序,默认值是 False 。如果该参数设置为 Ture ,那么编码结果的字典的键值会进行排序。示例:
1 | >>> print(json.dumps(person, ensure_ascii=False, indent=4, sort_keys=True)) |
更多参数请参阅:Python 3 的官方文档
解码
把 JSON 格式对象转换为 Python 对象称为解码,主要使用 json.load() 和 json.loads() 函数。这两个函数基本相同,区别类似于 json.dump() 和 json.dumps() 函数。下面主要以 json.loads() 函数为例,json.load() 函数的用法基本类似。
json.loads() 用法示例:
1 | >>> json.loads(json.dumps(person)) |
解码数据类型对应规则如下表:
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number (int) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
自定义类型处理
有时候,我们需要处理一些自定义的类型,例如有如下这个类:
1 | class Point: |
当我们要对其实例进行编码时会产生类似如下异常(文件路径有所省略):
1 | >>> person = { |
产生异常的原因是 JSON 默认的方法无法对这种 Python 对象进行编码。那么如何解决这个问题呢?主要有两种方法:
使用函数
1 | def my_default(o): |
输出结果如下:
1 | {"name": "dormouse", "point": [1, 2]} |
使用类
1 | class MyEncoder(json.JSONEncoder): |
输出结果如下:
1 | {"name": "dormouse", "point": [1, 2]} |
参考资料
注:
本文的 Python 环境为:
Python 3.6.2 |Continuum Analytics, Inc.| (default, Jul 20 2017, 13:51:32)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux