json 模块可以把一个 Python 对象编码为一个 JSON 字符串,还可以把 JSON 字符串解析为一个 Python 对象。
json 模块提供的功能和 pickle 模块类似,接口 API 也类似。pickle 模块是把对象序列化为一串字节流,可以保存或者传入另一个进程。json 模块是把对象编码为大家所熟知的 JavaScript 对象表达式 JSON(JavaScript Object Notation),在其他语言中很多都实现了 JSON 格式。它被大量应用于服务端、客户端通讯的接口,如:REST API,或者跨进程通讯的应用。
编码和解码数据 Encoding and Decoding
dumps() 方法把一个 Python 对象 转化为 JSON。
执行:
loads() 方法把一个 JSON 字符串转换为 Python 对象。
执行:
注意,解析 JSON 字符串生成的对象,键 d 是个列表类型,之前的对象是一个元组。
美化、压缩输出
JSON 字符串的可读性要比 pickle 生成的二进制要好。dumps() 方法可接收多个参数,使输出更方便阅读,例如 sort_keys 标志告诉编码器按照字典排序。
执行:
查看输出,传入 sort_keys=True 后, 键 a, c, d 按照字典顺序排序了。
如果是嵌套比较多的数据结构,可以使用 indent 参数指定一个整数值,代表缩进数量。
执行:
上面的例子,使用了 4 个单位长的缩进量。
separators 参数指定 JSON 字符串的分隔符,默认的分隔符是:(', ', ': '),逗号和冒号后面都有空格,请看下面的例子:
执行:
可以看到,指定了分隔符的输出字符数量减少了,这样可以用在生产环境中,减少传输的字节数量。
编码类型错误 TypeError
如果编码一个字典,字典类型的键 key 如果不是一个字符串,而是一个元组,会触发类型错误 TypeError 的异常。
元组可以作为字典的键,因为元组是不可变的。而列表是可变的,则不可以作为字典的键。
执行:
本例中,列表中的字典有一个键是元组,默认调用 dumps() 方法,触发了 TypeError 异常,提示键必须是字符串。后面使用 skipkeys 参数避免了触发异常,元组的键值并没有输出。
编码自定义类型
上面的例子都是 Python 的内置(built-in)类型,还有可能要编码自定义的类型。例如给出下面自定义的一个类型:
上面定义了模块 user,其中包含要编码的自定义类型: User。
通过下面的代码,我们就可以编码自定义的类型了,请看:
执行:
查看输出,第一次触发异常 TypeError,提示 <user> 不能 JSON。第二次传入了 default 参数,是一个 convert 函数,这个函数告诉编码器怎么编码自定义类型 User。最后返回的 JSON 就是 convert 返回的字典信息。/<user>
下面看一下,怎么使用 object_hook 参数把一个 JSON 字符串转换为自定义类型对象,object_hook 在解析的时候,把一个字典对象转换为自定义对象,所以最后他返回的就是自定义对象而不是字典。
执行:
查看输出,使用 object_hook 正确返回了自定义对象 User,注意 to_user() 函数首先使用了字典的 __class__ 和 __module__ 信息导入了 user 模块,然后使用了剩余的字典键值对,使用 **kwargs 语法实例化了自定义类型。
使用流和文件 Streams and Files
上面的例子,编码的数据结构都是存在内存中。json 还提供了便利的方法 load() 和 dump() 接收文件类型的对象(file-like object)。
执行:
上例中,使用 io 模块构造了一个文件对象,dump() 方法的第二个参数是文件对象,会把数据写入到文件对象,最后调用 getvalue() 方法打印了 JSON 字符串。
下面的例子,使用 load() 函数从文件读取 JSON 串转换为对象。
执行:
閱讀更多 趣喜歡編程 的文章