返回介绍

建议45:序列化的另一个不错的选择 JSON

发布于 2024-01-30 22:19:09 字数 3375 浏览 0 评论 0 收藏 0

JSON(JavaScript Object Notation)是一种轻量级数据交换格式,它基于JavaScript编程语言的一个子集,于1999年12月成为一个完全独立于语言的文本格式。由于其格式使用了其他许多流行编程的约定,如C、C++、C#、Java、JS、Python等,加之其简单灵活、可读性和互操作性较强、易于解析和使用等特点,逐渐变得流行起来,甚至有代替XML的趋势。关于JSON和XML之间的优劣,一直有很多争论,本书并不打算对这两者之间的是是非非做详尽的分析(笔者的观点是两者各有所长,在相当长的时间里还会共存共荣),这里关注的是JSON用于序列化方面的优势。在进行详细讨论之前,我们先来看看Python语言中对JSON的支持现状。

Python中有一系列的模块提供对JSON格式的支持,如simplejson、cjson、yajl、ujson,自Python2.6后又引入了标准库JSON。简单来说cjson和ujson是用C来实现的,速度较快。据cjson的文档表述:其速率比纯Python实现的json模块大概要快250倍。yajl是Cpython版本的JSON实现,而simplejson和标准库JSON本质来说无多大区别,实际上Python2.6中的json模块就是simplejson减去对Python2.4、2.5的支持以充分利用最新的兼容未来的功能。不过相对于simplejson,标准库更新相对较慢,Python2.7.5中simplejson对应的版本为2.0.9,而最新的simplejson的版本为3.3.0。在实际应用过程中将这两者结合较好的做法是采用如下import方法。

try: import simplejson as json
except ImportError: import json

本节仍采用标准库JSON来做一些探讨。Python的标准库JSON提供的最常用的方法与pickle类似,dump/dumps用来序列化,load/loads用来反序列化。需要注意的json默认不支持非ASCII-based的编码,如load方法可能在处理中文字符时不能正常显示,则需要通过encoding参数指定对应的字符编码。在序列化方面,相比pickle,JSON具有以下优势:

1)使用简单,支持多种数据类型。JSON文档的构成非常简单,仅存在以下两大数据结构。

名称/值对的集合。在各种语言中,它被实现为一个对象、记录、结构、字典、散列表、键列表或关联数组。

值的有序列表。在大多数语言中,它被实现为数组、向量、列表或序列。在Python中对应支持的数据类型包括字典、列表、字符串、整数、浮点数、True、False、None等。JSON中数据结构和Python中的转换并不是完全一一对应,存在一定的差异,读者可以自行查阅文档。Python中一个JSON文档可以分解为如图4-3所示形式。

2)存储格式可读性更为友好,容易修改。相比于pickle来说,json的格式更加接近程序员的思维,修改和阅读上要容易得多。dumps()函数提供了一个参数indent使生成的json文件可读性更好,0意味着“每个值单独一行”;大于0的数字意味着“每个值单独一行并且使用这个数字的空格来缩进嵌套的数据结构”。但需要注意的是,这个参数是以文件大小变大为代价的。如图4-4展示的是这两种格式之间的对比,其中json.dumps()使用了indent参数输出。

3)json支持跨平台跨语言操作,能够轻易被其他语言解析,如Python中生成的json文件可以轻易使用JavaScript解析,互操作性更强,而pickle格式的文件只能在Python语言中支持。此外json原生的JavaScript支持,客户端浏览器不需要为此使用额外的解释器,特别适用于Web应用提供快速、紧凑、方便的序列化操作。此外,相比于pickle,json的存储格式更为紧凑,所占空间更小。

图4-3 json文档分解图

图4-4 pickle和json文件格式对比

4)具有较强的扩展性。json模块还提供了编码(JSONEncoder)和解码类(JSONDecoder)以便用户对其默认不支持的序列化类型进行扩展。来看一个例子:

>>> d=datetime.datetime.now()
>>> d
datetime.datetime(2013, 9, 15, 8, 54, 59, 851000)
>>> json.dumps(d)
... ... ...
  raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2013, 9, 15, 8, 54, 59, 851000) is not JSON seriali
zable

5)json在序列化datetime的时候会抛出TypeError异常,这是因为json模块本身不支持datetime的序列化,因此需要对json本身的JSONEncoder进行扩展。有多种方法可以实现,下面的例子是其中实现之一。

import datetime
from time import mktime
try: import simplejson as json
except ImportError: import json
class DateTimeEncoder(json.JSONEncoder):    #
对JSONEncoder
进行扩展
  def default(self, obj):
    if isinstance(obj, datetime.datetime):
       return obj.strftime('%Y-%m-%d %H:%M:%S')
    elif isinstance(obj, date):
       return obj.strftime('%Y-%m-%d')
    return json.JSONEncoder.default(self, obj)
d=datetime.datetime.now()
print json.dumps(d, cls = DateTimeEncoder)    #
使用cls
指定编码器的名称

最后需要提醒的是,Python中标准模块json的性能比pickle与cPickle稍逊。如果对序列化性能要求非常高的场景,可以选择cPickle模块。图4-5显示的是这三者序列化时随着数据规模增加所消耗时间改变的图例。

图4-5 pickle、json、cPickle序列化文件时性能比较

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文