代码改变世界

自定义json模块的序列化

2019-08-12 11:13  美丽的名字  阅读(413)  评论(0)    收藏  举报

官方的json模块只能对Python支持的常见数据结构进行序列化,无法支持对于数据结构中存在自定义对象的数据的序列化。

样例数据:

{  

  "key1": 123,

  "key2": datatime.now()

}

 

对于上面的数据,如果用官方的json模块无法对datatime.now()这个对象进行序列化,所以需要对官方json模块进行定制以支持对该对象的序列化。

json.__init__.py

    # cached encoder
    if (not skipkeys and ensure_ascii and
        check_circular and allow_nan and
        cls is None and indent is None and separators is None and
        default is None and not sort_keys and not kw):
        return _default_encoder.encode(obj)
    if cls is None:
        cls = JSONEncoder
    return cls(
        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
        separators=separators, default=default, sort_keys=sort_keys,
        **kw).encode(obj)

  json.dumps方法中定义了默认的encoder就是JSONEncoder,在对数据进行dumps的时候会默认使用这个encoder,我们可以对它进行自定义。

 

json.encoder.py

通过default方法的描述,我们可以了解想要通过自定义实现对其他对象的序列化需要按照encode方法重写default方法

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for ``o``, or calls the base implementation
        (to raise a ``TypeError``).

        For example, to support arbitrary iterators, you could
        implement default like this::

            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return JSONEncoder.default(self, o)

        """
        raise TypeError(f'Object of type {o.__class__.__name__} '
                        f'is not JSON serializable')

    def encode(self, o):
        """Return a JSON string representation of a Python data structure.

        >>> from json.encoder import JSONEncoder
        >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
        '{"foo": ["bar", "baz"]}'

        """
        # This is for extremely simple cases and benchmarks.
        if isinstance(o, str):
            if self.ensure_ascii:
                return encode_basestring_ascii(o)
            else:
                return encode_basestring(o)
        # This doesn't pass the iterator directly to ''.join() because the
        # exceptions aren't as detailed.  The list call should be roughly
        # equivalent to the PySequence_Fast that ''.join() would do.
        chunks = self.iterencode(o, _one_shot=True)
        if not isinstance(chunks, (list, tuple)):
            chunks = list(chunks)
        return ''.join(chunks)

  

 

自定义JsonCustomEncoder类,重写父类json.JSONEncoder的default方法:

import json
from datetime import date
from datetime import datetime


class JsonCustomEncoder(json.JSONEncoder):

    def default(self, o):

        if isinstance(o, datetime):
            return o.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(o, date):
            return o.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, o)


d = {
    "key1": 123,
    "key2": datetime.now(),
}


ds = json.dumps(d, cls=JsonCustomEncoder)
print(ds)