Python继承JSONEncoder类,重写default,实现自定义序列化操作
json支持python的类型转化对象类型如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Supports the following objects and types by default:
+-------------------+---------------+ | Python | JSON | +===================+===============+ | dict | object | +-------------------+---------------+ | list, tuple | array | +-------------------+---------------+ | str | string | +-------------------+---------------+ | int, float | number | +-------------------+---------------+ | True | true | +-------------------+---------------+ | False | false | +-------------------+---------------+ | None | null | +-------------------+---------------+
|
可以看到,大部分的类型都可以通过json.dumps进行序列化,但是有些特殊的对象,例如事件对象,decimal.Decimal,以及uuid.UUID类型等。此时我们就需要手动重写default
方法,来实现对这些类型的序列化。
举个我的django项目中的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from datetime import datetime,date import json from decimal import Decimal from uuid import UUID
class JsonCustomEncoder(json.JSONEncoder): """对时间序列等特殊序列进行编码序列化""" def default(self, obj): if isinstance(obj,datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj,date): return obj.strftime('%Y-%m-%d') elif isinstance(obj,(Decimal,UUID,)): return str(obj) else: return super().default(obj)
|
接下来调用一下:
1 2 3 4 5 6
| dict_ = { 'name':'syz', 'age':21, 'hobby':'zjw', } m = json.dumps(dict_,cls=JsonCustomEncoder)
|
注:JSONEncoder应该会对传入的dict_
对象判断是否是可迭代对象,如果是,那么就进行迭代,依次判断里面元素是否满足json格式,如果不是,是一个对象的话,就会通过这个对象obj,手动来对obj里的属性进行json转化。
例如下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import json class Person: def __init__(name,age): self.name = name self.age = age
def transform(obj): return { 'name':obj.name, 'age':obj.age, }
p = Person()
j = json.dumps(p,default=transform)
|
最后阅读了一点源码,稍微分享一下阅读心得:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw): 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)
|
我们看这个cls参数,如果cls为None,就为cls打上默认的JSONEncoder猴子补丁,如果不为空,就说明有子类继承了JSONEncoder,传过来了参数,此时就调用JSONEncoder子类。
总结:其实不管是框架还是开源包,这样做的做法到处可见,最大的好处就是拓展性强,有效的实现解耦合。