注册 登录
  • 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Python模块:json

Python模块 彭东稳 5387次浏览 已收录 0个评论

一、什么是Json?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

注意,虽然在Python中单引号和双引号的作用完全相同。但是在其它语言中双引号引起来的才是字符串,单引号引起来的是字符!例如C,例如json!所以很多时候你可能会碰到在做Json格式转换时,经常发生使用单引号,导致转换失败的问题。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

JSON类型 Python类型
{} dict
[] list
“string” str
1234.56 int或float
true/false True/False
null None

二、JSON编码和解码

使用JSON函数需要导入json库:import json

函数 描述
json.dumps 将Python对象编码成JSON字符串
json.loads 将已编码的 JSON 字符串解码为Python对象

json.dumps

json.dumps用于将Python对象编码成JSON字符串。

语法

实例

以下实例将数组编码为JSON格式数据:

以上代码执行结果为:

使用参数让JSON数据格式化输出:

通过输出的结果可以看出,简单类型通过encode之后跟其原始的repr()输出结果非常相似,但是有些数据类型进行了改变,例如上例中的元组则转换为了列表。在json的编码过程中,会存在从python原始类型向json类型的转化过程,具体的转化参照上面的表格。

json.dumps方法提供了很多好用的参数可供选择,比较常用的有sort_keys(对dict对象进行排序,我们知道默认dict是无序存放的),separators,indent等参数。

上例中,本来data1和data2数据应该是一样的,但是由于dict存储的无序特性,造成两者无法比较。因此两者可以通过排序后的结果进行存储就避免了数据比较不一致的情况发生,但是排序后再进行存储,系统必定要多做一些事情,也一定会因此造成一定的性能消耗,所以适当排序是很重要的。

indent参数是缩进的意思,它可以使得数据存储的格式变得更加优雅。

输出的数据被格式化之后,变得可读性更强,但是却是通过增加一些冗余的空白格来进行填充的。json主要是作为一种数据通信的格式存在的,而网络通信是很在乎数据的大小的,无用的空格会占据很多通信带宽,所以适当时候也要对数据进行压缩。separator参数可以起到这样的作用,该参数传递是一个元组,包含分割对象的字符串。

执行结果如下:

通过移除多余的空白符,达到了压缩数据的目的,而且效果还是比较明显的。

另一个比较有用的dumps参数是skipkeys,默认为False。 dumps方法存储dict对象时,key必须是str类型,如果出现了其他类型的话,那么会产生TypeError异常,如果开启该参数,设为True的话,则会比较优雅的过度。

json.loads

json.loads用于解码JSON数据,该函数返回Python字段的数据类型。

语法:

实例:

以下实例展示了Python如何解码JSON对象。

以上代码执行结果为:

loads方法返回了原始的对象,但是仍然发生了一些数据类型的转化。比如,上例中转化为了unicode类型。从json到python的类型转化参考上面表格。

三、JSON进阶

Python的dict对象可以直接序列化为JSON的{},不过,很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化:

运行代码,毫不留情地得到一个TypeError:

错误的原因是Student对象不是一个可序列化为JSON的对象。

如果连class的实例对象都无法序列化为JSON,这肯定不合理! 通过上面所提到的json和python的类型转化对照表,可以发现,{}(object)类型是和dict相关联的,所以我们需要把我们自定义的类型转化为dict,然后再进行处理。这里,有两种方法可以使用。

方法一:自己写转化函数

仔细看看dumps()方法的参数列表,可以发现,除了第一个必须的obj参数外,dumps()方法还提供了一大堆的可选参数。这些可选参数就是让我们来定制JSON序列化。前面的代码之所以无法把Student类实例序列化为JSON,是因为默认情况下,dumps()方法不知道如何将Student实例变为一个JSON的{}对象。其中可选参数default就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为Student专门写一个转换函数,再把函数传进去即可:

这样,Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON:

不过,下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dict:

因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。也有少数例外,比如定义了__slots__的class。

同样的道理,如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例:

运行结果如下:

打印出的是反序列化的Student实例对象。

方法二:继承JSONEncoder和JSONDecoder类,覆写相关方法

JSONEncoder类负责编码,主要是通过其default函数进行转化,我们可以override该方法。同理对于JSONDecoder。

当继承JSONEncoder类后,我们就可以在default函数内做一些额外的处理,然后使用下面的方式解码出来。

 

 

利用继承的方式,我们可以很好地把时间类型转换为字符串类型,如下代码。

四、使用第三方库

Demjson是Python的第三方模块库,可用于编码和解码JSON数据,包含了JSONLint的格式化及校验功能。同时,simplejson也是一个序列号json的第三方库,在使用C扩展的情况下,速度比原生json快很多倍;另外,你如果有做数据库查询展示的需求,simplejson可以很好地处理bigint类型,不会丢失精度。如果使用原生json就会丢失bigint精度。

Github 地址:https://github.com/dmeranda/demjson

官方地址:http://deron.meranda.us/python/demjson

<参考>

http://www.runoob.com/python/python-json.html

http://www.cnblogs.com/coser/archive/2011/12/14/2287739.html


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (1)or分享 (0)
关于作者:

您必须 登录 才能发表评论!