JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。J SON有两种结构:第一种就是“名称/值”对的集合。在python中相当于字典类型,在其他语言中,它被理解为对象(object),纪 录(record),结构(struct),字典(dictionary),哈希表(hashtable),有键列表(keyedli st),或者关联数组(associativearray)。第二种就是值的有序列表。在大部分语言中,它被理解为数组(array) 。这两种都是常见的数据结构。大部分语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。jso n官方说明参见:http://json.org/Python操作json的标准api库参考:http://docs.python. org/library/json.html对简单数据类型的encoding和decoding:使用简单的json.dumps方 法对简单数据类型进行编码,例如:importjsonobj=[[1,2,3],123,123.123,''abc'',{''ke y1'':(1,2,3),''key2'':(4,5,6)}]encodedjson=json.dumps(obj)printre pr(obj)printencodedjson输出:[[1,2,3],123,123.123,''abc'',{''key 2'':(4,5,6),''key1'':(1,2,3)}][[1,2,3],123,123.123,"abc" ,{"key2":[4,5,6],"key1":[1,2,3]}]通过输出的结果可以看出,简单类型通过encode 之后跟其原始的repr()输出结果非常相似,但是有些数据类型进行了改变,例如上例中的元组则转换为了列表。在json的编码过程中,会 存在从python原始类型向json类型的转化过程,具体的转化对照如下:json.dumps()方法返回了一个str对象encod edjson,我们接下来在对encodedjson进行decode,得到原始数据,需要使用的json.loads()函数:deco dejson=json.loads(encodedjson)printtype(decodejson)printdecod ejson[4][''key1'']printdecodejson输出:[1,2,3][[1,2, 3],123,123.123,u''abc'',{u''key2'':[4,5,6],u''key1'':[1,2,3] }]loads方法返回了原始的对象,但是仍然发生了一些数据类型的转化。比如,上例中‘abc’转化为了unicode类型。从json 到python的类型转化对照如下:json.dumps方法提供了很多好用的参数可供选择,比较常用的有sort_keys(对dict 对象进行排序,我们知道默认dict是无序存放的),separators,indent等参数。排序功能使得存储的数据更加有利于观察, 也使得对json输出的对象进行比较,例如:data1={''b'':789,''c'':456,''a'':123}data2={''a '':123,''b'':789,''c'':456}d1=json.dumps(data1,sort_keys=True)d2=j son.dumps(data2)d3=json.dumps(data2,sort_keys=True)printd1prin td2printd3printd1==d2printd1==d3输出:{"a":123,"b":789,"c": 456}{"a":123,"c":456,"b":789}{"a":123,"b":789,"c":456}F alseTrue上例中,本来data1和data2数据应该是一样的,但是由于dict存储的无序特性,造成两者无法比较。因此两者可以 通过排序后的结果进行存储就避免了数据比较不一致的情况发生,但是排序后再进行存储,系统必定要多做一些事情,也一定会因此造成一定的性能 消耗,所以适当排序是很重要的。indent参数是缩进的意思,它可以使得数据存储的格式变得更加优雅。data1={''b'':789 ,''c'':456,''a'':123}d1=json.dumps(data1,sort_keys=True,indent=4)pr intd1输出:{"a":123,"b":789,"c":456}输出的数据被格式化之后,变得可读性更强,但是却是通 过增加一些冗余的空白格来进行填充的。json主要是作为一种数据通信的格式存在的,而网络通信是很在乎数据的大小的,无用的空格会占据很 多通信带宽,所以适当时候也要对数据进行压缩。separator参数可以起到这样的作用,该参数传递是一个元组,包含分割对象的字符串。 print''DATA:'',repr(data)print''repr(data):'',len(re pr(data))print''dumps(data):'',len(json.dumps(data))p rint''dumps(data,indent=2):'',len(json.dumps(data,indent=4))p rint''dumps(data,separators):'',len(json.dumps(data,separators= ('','','':'')))输出:DATA:{''a'':123,''c'':456,''b'':789}repr(data) :30dumps(data):30dumps(data,indent=2):4 6dumps(data,separators):25通过移除多余的空白符,达到了压缩数据的目的,而且效果还是比较明显的。另一个 比较有用的dumps参数是skipkeys,默认为False。dumps方法存储dict对象时,key必须是str类型,如果出现 了其他类型的话,那么会产生TypeError异常,如果开启该参数,设为True的话,则会比较优雅的过度。data={''b'':7 89,''c'':456,(1,2):123}printjson.dumps(data,skipkeys=True)输出:{"c": 456,"b":789}?处理自己的数据类型json模块不仅可以处理普通的python内置类型,也可以处理我们自定义的数据类 型,而往往处理自定义的对象是很常用的。首先,我们定义一个类Person。classPerson(object):def__i nit__(self,name,age):self.name=nameself.age=agedef__repr_ _(self):return''www.mntuku.cn:%s,age:%d''%(self.name,self .age)if__name__==''__main__'':p=Person(''Peter'',22)printp如果 直接通过json.dumps方法对Person的实例进行处理的话,会报错,因为json无法支持这样的自动转化。通过上面所提到的js on和python的类型转化对照表,可以发现,object类型是和dict相关联的,所以我们需要把我们自定义的类型转化为dict, 然后再进行处理。这里,有两种方法可以使用。方法一:自己写转化函数''''''Createdon2011-12-14@author: Peter''''''importPersonimportjsonp=Person.Person(''Peter'',22)de fobject2dict(obj):#convertobjecttoadictd={}d[''__class__ '']=obj.__class__.__name__d[''__module__'']=obj.__module__d.up date(obj.__dict__)returnddefdict2object(d):#convertdictto objectif''__class__''ind:class_name=d.pop(''__class__'')module _name=d.pop(''__module__'')module=__import__(module_name)clas s_=getattr(module,class_name)args=dict((key.encode(''ascii''), value)forkey,valueind.items())#getargsinst=class_(ar gs)#createnewinstanceelse:inst=dreturninstd=object2di ct(p)printd#{''age'':22,''__module__'':''Person'',''__class__'':''Pe rson'',''name'':''Peter''}o=dict2object(d)printtype(o),o#''Person.Person''>PersonObjectname:Peter,age:22dump=jso n.dumps(p,default=object2dict)printdump#{"age":22,"__module__" :"Person","__class__":"Person","name":"Peter"}load=json.l oads(dump,object_hook=dict2object)printload#PersonObjectname :Peter,age:22上面代码已经写的很清楚了,实质就是自定义object类型和dict类型进行转化。object 2dict函数将对象模块名、类名以及__dict__存储在dict对象里,并返回。dict2object函数则是反解出模块名、类名 、参数,创建新的对象并返回。在json.dumps方法中增加default参数,该参数表示在转化过程中调用指定的函数,同样在de code过程中json.loads方法增加object_hook,指定转化函数。方法二:继承JSONEncoder和JSONDec oder类,覆写相关方法JSONEncoder类负责编码,主要是通过其default函数进行转化,我们可以override该方法。 同理对于JSONDecoder。''''''Createdon2011-12-14@author:Peter''''''importP ersonimportjsonp=Person.Person(''Peter'',22)classMyEncoder(js on.JSONEncoder):defdefault(self,obj):#convertobjecttoadict d={}d[''__class__'']=obj.__class__.__name__d[''__module__'']= obj.__module__d.update(obj.__dict__)returndclassMyDecoder(j son.JSONDecoder):def__init__(self):json.JSONDecoder.__init__(s elf,object_hook=self.dict2object)defdict2object(self,d):#conve rtdicttoobjectif''__class__''ind:class_name=d.pop(''__class __'')module_name=d.pop(''__module__'')module=__import__(module_name)class_=getattr(module,class_name)args=dict((key.encode(''ascii''),value)forkey,valueind.items())#getargsinst=class_(args)#createnewinstanceelse:inst=dreturninstd=MyEncoder().encode(p)o=MyDecoder().decode(d)printdprinttype(o),o |
|