PyMOTW: json
json模块提供了一个类似于pickle中用于转换内存中python对象为一个序列表示形式(“JavaScript Object Notation”)的API接口. 但和pickle不同的是, JSON在其他很多语言中都有对应实现(特别是在JavaScript中), 使其更适用于内部应用间的通信. 在一个AJAX应用中, JSON可能对于web服务器和客户端间的通信, 使用最为广泛, 但它也不仅限于这类应用.
简单数据类型的编码和解码
编码器默认支持Python的本地类型(如int, float, list, tuple, dict).
编码器处理之后的值和Python的repr()的输出值很类似.
编码之后的解码所获的的值可能和原先的对象不是完全一致.
比如说, 元组会被转换为JSON的列表.
人性化使用 vs 紧凑型输出
JSON优于pickle的另外一点是其结果具有可读性. dumps()函数接收多个参数用于更好的输出结构. 比如说. sort_keys参数告诉编码器按照顺序输出字典的键值, 而不是随机无序的.
排序之后更容易让人看出结果, 也使进行JSON的比较输出成为可能.
对于高度嵌套的数据结构, 你会想在输出结果中增加缩进以更好的显示其格式.
当indent参数是一非负整数时, 输出的结构和pprint更为接近, 在每个缩进层次上都有前导空格.
像这种类型输出的数据在传输过程中需占用更多的字节, 不过, 在实际生产环境中没有必要使用缩进格式. 实际上, 你可以设置数据的分隔符来让结果更为紧凑.
dumps()函数的separators参数是一个元组, 包含分隔列表各项和字典键值各项的字符串. 默认是(‘, ‘, ‘: ‘). 可以去掉后者中的空格, 我们可以得到较紧凑的输出.
编码字典
JSON格式中, 字典的键被限制为字符串类型. 如果字典中的键是其他类型, 那么在编码这个对象时会产生一个TypeError异常. 一种解决这个限制的方法是, 在编码时, 使用skipkeys参数跳过所有非字符串类型的键.
非字符串类型的键被忽略, 而不抛出一个异常.
自定义类型的处理
上面所有的例子都是用了Python的内置类型作为例子, 因为他们都被json本身支持. 当然, 自定义类型也常常需要正确编码. 这里有两种情况:
第一, 对于一个类的编码:
编码一个MyObj对象的最简单方式是定义个转换函数, 用于将位置类型转换出呢个已知类型. 你没有必要自己进行编码, 而仅需要将一个对象转换成另一个对象.
在convert_to_builtin_type()函数中, 不被json识别的类对象被转换成一个包含足够能重建这个对象的字典信息.
为了能解码结果数据并创建一个MyObj实例, 我们需要配合解码器以便可以从模块中导入类并创建实例. 我们在loads()函数中使用object_hook参数.
在输入数据流中, 对于解码获得的每个字典都会调用object_hook, 将这个字典转换成其他类型的对象. hook函数返回的是调用程序所需要的对象, 而不是字典.
由于json将字符串值转换成unicode对象, 所以我们需要将作为类构造器的参数重新编码为ASCII字符串.
对于内置类型也都有类似的hooks, 如整型(parse_int), 浮点型(parse_float), 常量(parse_constant).
编码和解码类
除了上述的这些函数外, json模块还提供了编码和解码类. 直接使用这些类, 你可以访问到额外的API接口或者定制创建它的子类.
JSONEncoder提供了一个产生编码数据”块”的的迭代接口, 这在写入一个文件或网络sockets时(不需要在内存中完整表示整个数据)是非常方便的,
正如你看到的, 数据是以逻辑单位形式输出的, 而不是按照数据长度输出.
encode()方法基本上等价于’‘.join(encoder.iterencode()), 只是多了些附加错误检查.
为了能够编码任何类型的对象, 我们可以编写一类似于上述的convert_to_builtin_type()函数去重载default()方法.
这里输出的结果是和先前的实现一致的.
解码后将字典转换成一个对象, 在先前实现的基础上稍作修改即可.
输出结果也是和先前例子中输出的一样.
流和文件的处理
到目前为止的所有例子, 我们都假设待编码的数据都是一次性完整加载到内存中的. 但对于大型数据结构来说, 将编码数据直接写入一个类文件对象, 可能会更好. load()和dump()函数可以接收一个用于读或写的类文件对象的引用.
对于socket来说, 也和正常文件句柄类似.
虽然一次性读取部分数据不是很好, 但是load()函数仍然提供了从流数据输入中封装生成对象的功能.
混合数据流
JSONDecoder包含了raw_decode()方法, 用于解码在很多数据组成的数据结构, 例如包含多余文本的JSON数据. 返回的值是从输入数据中解码获得的对象, 数据中的index表示解码对象结束时所在的位置.
不幸的是, 这仅仅在对象出现在输入流的开始处才有效.
原文地址: