JSON进阶
Python的 dict 对象可以直接序列化为JSON的 {} ,不过,很多时候,我们更喜欢用 class 表示对象,比如定义 Student 类,然后序列化:
import json
class Student(object):
def init(self, name, age, score):
self.name = name
self.age = age
self.score = score
s = Student('Bob', 20, 88)
print(json.dumps(s))
运行代码,毫不留情地得到一个 TypeError :
Traceback (most recent call last):
…
TypeError: <main.Student object at 0x10603cc50> is not JSON serializable
错误的原因是 Student 对象不是一个可序列化为JSON的对象。
如果连 class 的实例对象都无法序列化为JSON,这肯定不合理!
别急,我们仔细看看 dumps() 方法的参数列表,可以发现,除了第一个必须的 obj 参数外, dumps() 方法还提供了一大堆的可选参数:
https://docs.python.org/3/library/json.html#json.dumps
这些可选参数就是让我们来定制JSON序列化。前面的代码之所以无法把 Student 类实例序列化为JSON,是因为默认情况下, dumps() 方法不知道如何将 Student 实例变为一个JSON的 {} 对象。
可选参数 default 就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为 Student 专门写一个转换函数,再把函数传进去即可:
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
这样, Student 实例首先被 student2dict() 函数转换成 dict ,然后再被顺利序列化为JSON:
>>> print(json.dumps(s, default=student2dict))
{"age": 20, "name": "Bob", "score": 88}
不过,下次如果遇到一个 Teacher 类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意 class 的实例变为 dict :
print(json.dumps(s, default=lambda obj: obj.dict))
因为通常 class 的实例都有一个 dict 属性,它就是一个 dict ,用来存储实例变量。也有少数例外,比如定义了 slots 的class。
同样的道理,如果我们要把JSON反序列化为一个 Student 对象实例, loads() 方法首先转换出一个 dict 对象,然后,我们传入的 object_hook 函数负责把 dict 转换为 Student 实例:
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
运行结果如下:
>>> jsonstr = '{"age": 20, "score": 88, "name": "Bob"}'
>>> print(json.loads(jsonstr, object_hook=dict2student))
<__main.Student object at 0x10cd3c190>
打印出的是反序列化的 Student 实例对象。