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 实例对象。