Free Will

python编程系列(2):JSON

一、Json简介

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

存储在SQL数据库中的数据往往是规整的,比如这里有一个SQLite数据库的例子:

1
2
3
4
id|code|name|area|area_land|area_water|population|population_growth|birth_rate|death_rate|migration_rate|created_at|updated_at
1|af|Afghanistan|652230|652230|0|32564342|2.32|38.57|13.89|1.51|2015-11-01 13:19:49.461734|2015-11-01 13:19:49.461734
2|al|Albania|28748|27398|1350|3029278|0.3|12.92|6.58|3.3|2015-11-01 13:19:54.431082|2015-11-01 13:19:54.431082
3|ag|Algeria|2381741|2381741|0|39542166|1.84|23.67|4.31|0.92|2015-11-01 13:19:59.961286|2015-11-01 13:19:59.961286

上述的数据由行和列组成,其中每列映射到一个已定义的属性,如id或者name。其中每一行代表一个国家,每一列代表了这个国家一些特征。但随着数据量的增加,在存储的时候我们通常不知道数据的确切的结构,这被称为非结构化数据。一个很好的例子就是网站上的访客列表,下面是发送到服务器的事件列表的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{'event_type': 'started-mission',
'keen': {'created_at': '2015-06-12T23:09:03.966Z',
'id': '557b668fd2eaaa2e7c5e916b',
'timestamp': '2015-06-12T23:09:07.971Z'},
'sequence': 1}
{'event_type': 'started-screen',
'keen': {'created_at': '2015-06-12T23:09:03.979Z',
'id': '557b668f90e4bd26c10b6ed6',
'timestamp': '2015-06-12T23:09:07.987Z'},
'mission': 1,
'sequence': 4,
'type': 'code'}
{'event_type': 'started-screen',
'keen': {'created_at': '2015-06-12T23:09:22.517Z',
'id': '557b66a246f9a7239038b1e0',
'timestamp': '2015-06-12T23:09:24.246Z'},
'mission': 1,
'sequence': 3,
'type': 'code'},

上面列出了三个独立事件。每个事件都有不同的字段,有些字段嵌套在其他字段中。这种类型的数据很难在常规的SQL数据库中存储。所以这种非结构化数据通常以JavaScript对象表示法(JSON)格式存储。JSON是一种将列表和字典等数据结构编码成字符串的方法,这样来确保它们易于被机器读取。尽管JSON以Javascript开头,但它实际上只是一种格式,可以通过任何语言读取。

Json对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

它的值可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。

二、Python编码和解析Json

Python有很大的JSON支持。我们可以将列表和字典转换为JSON,并将字符串转换为列表和字典。JSON数据看起来很像Python中的字典(dictionary),其中存储了键和值。

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

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

将Python的字典结构导出到json使用json.dumps(),将json读成Python的字典结构,使用json.loads()
如果不是针对string操作而是对文件操作,分别使用json.load()函数和json.dump()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import json
from pprint import pprint
data = [
{'event_type': 'started-mission',
'keen': {'created_at': '2015-06-12T23:09:03.966Z',
'id': '557b668fd2eaaa2e7c5e916b',
'timestamp': '2015-06-12T23:09:07.971Z'},
'sequence': 1},
{'event_type': 'started-screen',
'keen': {'created_at': '2015-06-12T23:09:03.979Z',
'id': '557b668f90e4bd26c10b6ed6',
'timestamp': '2015-06-12T23:09:07.987Z'},
'mission': 1,
'sequence': 4,
'type': 'code'}
]
json_str = json.dumps(data, sort_keys=True, indent=1, separators=(',', ': '))
data = json.loads(json_str)
print type(json_str)
print type(data)
pprint(data)
# Writing JSON data to file
with open('data.json', 'w') as f:
json.dump(data, f)
# Reading data back
with open('data.json', 'r') as f:
data = json.load(f)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<type 'str'>
<type 'list'>
[{u'event_type': u'started-mission',
u'keen': {u'created_at': u'2015-06-12T23:09:03.966Z',
u'id': u'557b668fd2eaaa2e7c5e916b',
u'timestamp': u'2015-06-12T23:09:07.971Z'},
u'sequence': 1},
{u'event_type': u'started-screen',
u'keen': {u'created_at': u'2015-06-12T23:09:03.979Z',
u'id': u'557b668f90e4bd26c10b6ed6',
u'timestamp': u'2015-06-12T23:09:07.987Z'},
u'mission': 1,
u'sequence': 4,
u'type': u'code'}]

在编码JSON的时候,这里我们为了获得漂亮的格式化字符串,可以使用 json.dumps() 的indent参数。 它会使得输出和pprint()函数效果类似。

默认的类型对应如下:

JSON Python
object dict
array list
string unicode
number (int) int, long
number (real) float
true True
false False
null None

三、其他数据类型与Json之间的编码和解码

一般来讲,JSON解码会根据提供的数据创建dicts或lists。 如果你想要创建其他类型的对象,可以给 json.loads() 传递object_pairs_hook或object_hook参数。 例如,下面是演示如何解码JSON数据并在一个OrderedDict中保留其顺序的例子:

1
2
3
4
from collections import OrderedDict
s = '{"name": "ACME", "shares": 50, "price": 490.1}'
data = json.loads(s, object_pairs_hook=OrderedDict)
data
1
OrderedDict([(u'name', u'ACME'), (u'shares', 50), (u'price', 490.1)])

下面是如何将一个JSON字典转换为一个Python对象例子:

1
2
3
4
5
6
7
s = '{"name": "ACME", "shares": 50, "price": 490.1}'
class JSONObject:
def __init__(self, d):
self.__dict__ = d
data = json.loads(s, object_hook=JSONObject)

这里,JSON解码后的字典作为一个单个参数传递给 __init__() 。 然后,就可以随心所欲的使用了,比如作为一个实例字典来直接使用它。

1
2
data.name
data.price
1
2
ACME
490.1

对象实例通常并不是JSON可序列化的。例如:

1
2
3
4
5
6
7
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(2, 3)
json.dumps(p)
1
TypeError: <__main__.Point instance at 0x10aa97c20> is not JSON serializable

如果你想序列化对象实例,你可以提供一个函数,它的输入是一个实例,返回一个可序列化的字典。例如:

1
2
3
4
def serialize_instance(obj):
d = { '__classname__' : type(obj).__name__ }
d.update(vars(obj))
return d

下面是如何使用这些函数的例子:

1
2
3
4
5
6
7
8
def serialize_instance(obj):
d = { '__classname__' : type(obj).__name__ }
d.update(vars(obj))
return d
p = Point(2,3)
s = json.dumps(p, default=serialize_instance)
1
'{"y": 3, "x": 2, "__classname__": "instance"}'


应统联盟


连接十万名应统专业同学


阿药算法


打通算法面试任督二脉