概念:

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

JSON建构于两种结构:

  • “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
  • 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。

序列化(Serialization):将对象的状态信息转换为可以存储或可以通过网络传输的过程,传输的格式可以是JSON、XML等。反序列化就是从存储区域(JSON,XML)读取反序列化对象的状态,重新创建该对象。

Python2.6开始加入了JSON模块,无需另外下载,Python的Json模块序列化与反序列化的过程分别是 encoding和 decoding

encoding:把一个Python对象编码转换成Json字符串
decoding:把Json格式字符串解码转换成Python对象
对于简单数据类型(string、unicode、int、float、list、tuple、dict),可以直接处理。

json详细讲解参见:http://json.org/json-zh.html

Python操作json的标准api库参考:https://docs.python.org/3/library/json.html

1、简单数据类型的encoding和decoding:

>>> import json
>>> obj = [[1,2,3], 12, 12.3, 'abc', {123:(1,2,3), 'key1':[1,2], 'key2':[3,4]}]
>>> encodedjson = json.dumps(obj)
>>> print(repr(obj))
[[1, 2, 3], 12, 12.3, 'abc', {'key1': [1, 2], 123: (1, 2, 3), 'key2': [3, 4]}]
>>> print(encodedjson)
[[1, 2, 3], 12, 12.3, "abc", {"key1": [1, 2], "123": [1, 2, 3], "key2": [3, 4]}]
>>>

简单类型的数据通过encode之后与原始的repr()输出结果神似;部分数据类型存在差异,例如上例中的元组转换为列表,字典中键为123的整型转化为字符串类型。在json的编码过程中,会存在从python原始类型向json类型的转化过程,具体的转化对照如下:

json.dumps()方法返回了一个str对象encodedjson,json.loads()函数可以将encodedjson进行decode,得到原始数据:

>>> decodedjson = json.loads(encodedjson)
>>> print(type(decodedjson))
<class 'list'>
>>> print(decodedjson)
[[1, 2, 3], 12, 12.3, 'abc', {'key1': [1, 2], '123': [1, 2, 3], 'key2': [3, 4]}]
>>> print(decodedjson[4]['123'])
[1, 2, 3]
>>>

注意上述decodedjson[4]['123']的键仍为字符串,并未转化为原始的数据类型(int),建议在字典key中采用基本的字符串类型。

>>> kk = {1:[1,2,3],False:[3,5],None:2}
>>> kkd = json.dumps(kk)
>>> print(kkd)
{"false": [3, 5], "1": [1, 2, 3], "null": 2}
>>> kkl = json.loads(kkd)
>>> print(kkl)
{'1': [1, 2, 3], 'null': 2, 'false': [3, 5]}
>>>

从json到python的类型转化对照如下:

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

排序功能使得存储的数据更加有利于观察,也使得对json输出的对象进行比较,例如:

>>> data_1 = {'b':789, 'c':456, 'a':123}
>>> data_2 = {'a':123, 'b':789, 'c':456}
>>> d1 = json.dumps(data_1, sort_keys=True)
>>> d2 = json.dumps(data_2)
>>> d3 = json.dumps(data_2, sort_keys=True)
>>> print(d1)
{"a": 123, "b": 789, "c": 456}
>>> print(d2)
{"c": 456, "b": 789, "a": 123}
>>> print(d3)
{"a": 123, "b": 789, "c": 456}
>>> print(d1 == d2)
False
>>> print(d1 == d3)
True
>>> print(data_1 == data_2)
True
>>>

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

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

>>> data_1 = {'b':789, 'c':456, 'a':123}
>>> d1 = json.dumps(data_1, sort_keys=True, indent=4)
>>> print(d1)
{
"a": 123,
"b": 789,
"c": 456
}
>>>

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

>>> data = {'b':789, 'c':456, 'a':123}
>>> print('DATA:',repr(data))
DATA: {'c': 456, 'a': 123, 'b': 789}
>>> print('repr(data) :', len(repr(data)))
repr(data) : 30
>>> print('dumps(data) :', len(json.dumps(data)))
dumps(data) : 30
>>> print('dumps(data, indent=4) :', len(json.dumps(data, indent = 4)))
dumps(data, indent=4) : 44
>>> print('dumps(data, separators):', len(json.dumps(data, separators=(',', ':'))))
dumps(data, separators : 25
>>>

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

>>> data = {'b':789,'c':456,(1,2):123, 456:678}
>>> print(json.dumps(data))
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
print(json.dumps(data))
File "D:\Python\lib\json\__init__.py", line 230, in dumps
return _default_encoder.encode(obj)
File "D:\Python\lib\json\encoder.py", line 192, in encode
chunks = self.iterencode(o, _one_shot=True)
File "D:\Python\lib\json\encoder.py", line 250, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string
>>> print(json.dumps(data, skipkeys=True))
{"456": 678, "b": 789, "c": 456}
>>>

2、处理自定义的数据类型:

json模块不仅可以处理普通的python内置类型,也可以处理我们自定义的数据类型,而往往处理自定义的对象是很常用的。

首先,我们在Person模块中定义一个类Person。

#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
# autor:antclonies import json class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return 'Person Object name : %s, age : %d'%(self.name, self.age) if __name__ == '__main__':
p = Person('Peter', 22)
print(p)
dmp = json.dumps(p)
print(dmp)

运行以上模块:

[root@ant-colonies tmp]# ./py_2.py
Person Object name : Peter, age : 22
Traceback (most recent call last):
...
File "/usr/local/lib/python3.5/json/encoder.py", line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: Person Object name : Peter, age : 22 is not JSON serializable

如果直接通过json.dumps方法对Person的实例进行处理的话,会报错,因为json不知道怎样转化这个Person类型的实例p。通过上面所提到的json和python的类型转化对照表,可以发现,object类型和dict相关联,所以我们需要把我们自定义的类型转化为dict,然后再进行处理。这里,有两种方法可以使用。

方法一:自己写转化函数

#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
# import json
import Person p = Person.Person('Peter', 22) def obj2dict(obj):
'''convert object to dict'''
d = {}
d['__class__'] = obj.__class__.__name__
d['__module__'] = obj.__module__
d.update(obj.__dict__)
return d def dict2obj(dmp):
'''convert dict to object'''
if '__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
module = __import__(module_name)
class_ = getattr(module, class_name)
args = dict((key, value) for key, value in d.items()) # get args
inst = class_(**args) # create new instance
else:
inst = d
return inst d = obj2dict(p)
print(d)
'''{'__module__': 'Person', '__class__': 'Person', 'name': 'Peter', 'age': 22}''' o = dict2obj(d)
print(type(o), o)
'''<class 'Person.Person'> Person Object name : Peter, age : 22''' dump = json.dumps(p, default=obj2dict)
print(dump)
'''{"__module__": "Person", "__class__": "Person", "name": "Peter", "age": 22}''' load = json.loads(dump, object_hook=dict2obj)
print(load)
'''{'name': 'Peter', 'age': 22}'''

上面代码已经写的很清楚了,实质就是自定义object类型和dict类型进行转化。object2dict函数将对象模块名、类名以及__dict__存储在dict对象里,并返回。dict2object函数则是反解出模块名、类名、参数,创建新的对象并返回。在json.dumps 方法中增加default参数,该参数表示在转化过程中调用指定的函数,同样在decode过程中json.loads方法增加object_hook,指定转化函数。

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

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

#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
# import json
import Person p = Person.Person('Peter', 22) class MyEncoder(json.JSONEncoder):
def default(self, obj):
'''convert object to dict'''
d = {}
d['__class__'] = obj.__class__.__name__
d['__module__'] = obj.__module__
d.update(obj.__dict__)
return d class MyDecoder(json.JSONDecoder):
def __init__(self):
json.JSONDecoder.__init__(self, object_hook=self.dict2obj)
def dict2obj(self, d):
'''convert dict to object'''
if '__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
module = __import__(module_name)
class_ = getattr(module, class_name)
args = dict((key, value) for key, value in d.items()) # get args
inst = class_(**args) # create new instance
else:
inst = d
return inst d = MyEncoder().encode(p)
o = MyDecoder().decode(d) print(d)
print(type(o), o) '''
{"name": "Peter", "age": 22, "__module__": "Person", "__class__": "Person"}
<class 'Person.Person'> Person Object name : Peter, age : 22
'''

参考了:

http://www.cnblogs.com/coser/archive/2011/12/14/2287739.html
https://docs.python.org/3/library/json.html
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143192607210600a668b5112e4a979dd20e4661cc9c97000

Python 中数据的序列化和反序列化(json处理)的更多相关文章

  1. python中class的序列化和反序列化

    对于类的序列化:将类的成员变量名和数据作为一对键值对存储在物理内存中,例如 class A(object): def __init__(self): self.a = o self.b = 1 sel ...

  2. day5-python中的序列化与反序列化-json&pickle

    一.概述 玩过稍微大型一点的游戏的朋友都知道,很多游戏的存档功能使得我们可以方便地迅速进入上一次退出的状态(包括装备.等级.经验值等在内的一切运行时数据),那么在程序开发中也存在这样的需求:比较简单的 ...

  3. Jackson序列化和反序列化Json数据完整示例

    Jackson序列化和反序列化Json数据 Web技术发展的今天,Json和XML已经成为了web数据的事实标准,然而这种格式化的数据手工解析又非常麻烦,软件工程界永远不缺少工具,每当有需求的时候就会 ...

  4. 对 JSON 数据进行序列化和反序列化

    如何:对 JSON 数据进行序列化和反序列化 2017/03/30 作者 JSON(JavaScript 对象符号)是一种高效的数据编码格式,可用于在客户端浏览器和支持 AJAX 的 Web 服务之间 ...

  5. Json数据的序列化与反序列化的三种经常用法介绍

    下面内容是本作者从官网中看对应的教程后所做的demo.其体现了作者对相关知识点的个人理解..作者才疏学浅,难免会有理解不到位的地方.. 还请各位读者批判性对待... 本文主要介绍在Json数据的序列化 ...

  6. python之数据的序列化

    参考博客:http://www.cnblogs.com/yyds/p/6563608.html 数据的序列化功能表 json.dumps() 将python数据类型转换为(json)字符串 json. ...

  7. Python 入门之 内置模块 -- 序列化模块(json模块、pickle模块)

    Python 入门之 内置模块 -- 序列化模块(json模块.pickle模块) 1.序列化 Python中这种序列化模块有三种: ​ json模块 : ​ 不同语言都遵循的一种数据转化格式,即不同 ...

  8. C#序列化及反序列化Json对象通用类JsonHelper

    当今的程序界Json大行其道.因为Json对象具有简短高效等优势,广受广大C#码农喜爱.这里发一个序列化及反序列化Json对象通用类库,希望对大家有用. public class JsonHelper ...

  9. (推荐JsonConvert )序列化和反序列化Json

    在Json文本和.Net对象之间转换最快的方法是试用JsonSerializer. JsonSerializer通过将.Net对象属性名称映射到Json属性名称,并为其复制值,将.Net对象转换为其J ...

随机推荐

  1. C# File类常用方法

    File 类 提供用于创建.复制.删除.移动和打开文件的静态方法,并协助创建 FileStream 对象. 1. File.Exists ——  确定指定的文件是否存在. public static ...

  2. 小议C#接口的隐式与显示实现(续)

    上文连接,讲的比较模糊,而且调用起来感觉比较混乱 http://www.cnblogs.com/walleyekneel/p/3581489.html 这次改为显式接口调用,可能项目也有这个一个需求 ...

  3. 父级(display:none)隐藏时,子节点的高度获取。

    当父节点display:none的时候,子节点的高度是0获取不到. 解决办法:用visibility替换display就可以了.

  4. sql中日期转换

    date_format的函数使用令日期格式转换变得十分便捷首先先说一个自己粗心踩到的坑.因为最开始自己建的表里面存的数据,已经固定是周一的时间了,然后有一个状态判断是需要拿到所有周一是否有数据,当时忘 ...

  5. [SinGuLaRiTy] 树链问题

    [SinGuLaRiTy-1035] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 关于树链 树链是什么?这个乍一看似乎很陌生的词汇表达的其 ...

  6. html->head->body

    ps:大师兄的博客链接http://www.imdsx.cn/ http://ui.imdsx.cn/html/ html 相当于一个人 css 相当于为这个人穿上漂亮的衣服,化妆 js    相当于 ...

  7. 通过 js 修改 html 的文本内容或者样式

    通过 js 修改 html 的文本内容 <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...

  8. Struts、Hibernate和Spring的整合

    Spring整合Hibernate Spring以其开放性,能与大部分ORM框架良好的整合.这样Spring就能轻松地使用ORM. Spring提供了DAO支持,DA0组件是应用的持久层访问的重要组件 ...

  9. mysql 面试题

    1.一张表,里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把Mysql重启,再insert一条记录,这条记录的ID是18还是15 ?   2.Mysql的技术特 ...

  10. 用IDM下载博客图片

    前言 写博客的人一定都会有一个图床,将图片存在那里.发现自己以前没有注意图片来源问题,随手就贴在博客上面了.现在有不少图片都挂了,换句话来说有可能自己目前用的图床不提供服务了,那所有的图片都有可能丢失 ...