hor*_*cex 22 python mysql json tornado ios5
是否有任何优雅的方式使Python JSON编码器支持日期时间?一些第三方模块或简单的黑客?
我正在使用龙卷风的数据库包装器从db中获取一些原始数据以生成json.查询结果包括常规MySQL时间戳列.
Python的默认json编码器不支持自己的日期时间类型,这是非常烦人的,这在所有类型的数据库查询中都很常见.
我不想修改Python自己的json编码器.任何好的做法?非常感谢!
ps:我通过修改Python JSON编码器默认方法找到了一个脏黑客:
更改:
def default(self, o):
    raise TypeError(repr(o) + " is not JSON serializable")
至:
def default(self, o):
    from datetime import date
    from datetime import datetime
    if isinstance(o, datetime):
        return o.isoformat()
    elif isinstance(o, date):
        return o.isoformat()
    else:
        raise TypeError(repr(o) + " is not JSON serializable")
好吧,它只是开发环境的临时解决方案.
但是对于长期解决方案或生产环境,这非常难看,每次部署到新服务器时我都必须进行修改.
有没有更好的办法?我不想修改Python代码本身,也不想修改Tornado源代码.我能用自己的项目代码做些什么来实现这一目标吗?最好是一步到位.
非常感谢!
Dav*_*nes 29
json.dumps(thing, default=str)
Col*_*ean 22
文档建议继承JSONEncoder并实现自己的默认方法.好像你基本上就在那里,而且这不是一个"肮脏的黑客".
默认编码器不处理日期的原因是JSON中没有日期的标准表示.有些人正在使用这种格式/Date(1198908717056)/,但我个人更喜欢ISO格式.
import json
import datetime
class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
            return obj.isoformat()
        elif isinstance(obj, datetime.timedelta):
            return (datetime.datetime.min + obj).time().isoformat()
        return super(DateTimeEncoder, self).default(obj)
now = datetime.datetime.now()
encoder = DateTimeEncoder()
encoder.encode({"datetime": now, "date": now.date(), "time": now.time()})
> {"datetime": "2019-07-02T16:17:09.990126", "date": "2019-07-02", "time": "16:17:09.990126"}
Szi*_*dam 10
我为我的项目创建了自己的类:
import datetime
import decimal
import json
import sys
class EnhancedJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            ARGS = ('year', 'month', 'day', 'hour', 'minute',
                     'second', 'microsecond')
            return {'__type__': 'datetime.datetime',
                    'args': [getattr(obj, a) for a in ARGS]}
        elif isinstance(obj, datetime.date):
            ARGS = ('year', 'month', 'day')
            return {'__type__': 'datetime.date',
                    'args': [getattr(obj, a) for a in ARGS]}
        elif isinstance(obj, datetime.time):
            ARGS = ('hour', 'minute', 'second', 'microsecond')
            return {'__type__': 'datetime.time',
                    'args': [getattr(obj, a) for a in ARGS]}
        elif isinstance(obj, datetime.timedelta):
            ARGS = ('days', 'seconds', 'microseconds')
            return {'__type__': 'datetime.timedelta',
                    'args': [getattr(obj, a) for a in ARGS]}
        elif isinstance(obj, decimal.Decimal):
            return {'__type__': 'decimal.Decimal',
                    'args': [str(obj),]}
        else:
            return super().default(obj)
class EnhancedJSONDecoder(json.JSONDecoder):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, object_hook=self.object_hook,
                         **kwargs)
    def object_hook(self, d): 
        if '__type__' not in d:
            return d
        o = sys.modules[__name__]
        for e in d['__type__'].split('.'):
            o = getattr(o, e)
        args, kwargs = d.get('args', ()), d.get('kwargs', {})
        return o(*args, **kwargs)
if __name__ == '__main__':
    j1 = json.dumps({'now': datetime.datetime.now(),
        'val': decimal.Decimal('9.3456789098765434987654567')},
        cls=EnhancedJSONEncoder)
    print(j1)
    o1 = json.loads(j1, cls=EnhancedJSONDecoder)
    print(o1)
结果:
{"val": {"args": ["9.3456789098765434987654567"], "__type__": "decimal.Decimal"}, "now": {"args": [2014, 4, 29, 11, 44, 57, 971600], "__type__": "datetime.datetime"}}
{'val': Decimal('9.3456789098765434987654567'), 'now': datetime.datetime(2014, 4, 29, 11, 44, 57, 971600)}
参考文献:
注意:通过将类型为键和args,kwargs作为值传递给编码器的自定义字典并__init__()在default()方法中使用(或默认字典),可以使其更加灵活.
小智 6
json.dumps(r, default=lambda o: o.isoformat() if hasattr(o, 'isoformat') else o)