Python

pythonでjson出力する際で対応していない型(e.g. datetime)の値を変換しながら出力したい

More than 3 years have passed since last update.

pythonでjson出力する際で対応していない型(e.g. datetime)の値を変換しながら出力したい。

対応していない型を含んだ辞書でTypeErrorが発生

pythonでdictをjsonに変換しようとする際にはjson.dumps(json.dump)が使える。
この時、対応していないされていない型の値が含まれていた場合には以下の様な例外が発生する。

# TypeError: datetime.datetime(2000, 1, 1, 0, 0) is not JSON serializable

例えば、datetime objectを含んだ辞書personをjson.dumps仕様とした際には以下のような結果になってしまう。

import json
from datetime import datetime

person = {
    "name": "Foo",
    "age": 20,
    "created_at": datetime(2000, 1, 1)
}

json.dumps(person)
# TypeError: datetime.datetime(2000, 1, 1, 0, 0) is not JSON serializable

default引数に関数を与えることで、対応していない型に対するコールバックを設定する事ができる

json.dumpsは幾つかの引数を取れる。

json.dumps = dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, inden
t=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw)
    Serialize ``obj`` to a JSON formatted ``str``.
...

この内のdefault引数に以下のような関数を与えてあげると、対応していない方に対するマッピングを後付で指定することができる。

def support_datetime_default(o):
    if isinstance(o, datetime):
        return o.isoformat()
    raise TypeError(repr(o) + " is not JSON serializable")

今度はjson.dumpsで変換することができる。

person = {
    "name": "Foo",
    "age": 20,
    "created_at": datetime(2000, 1, 1)
}


json.dumps(person, default=support_datetime_default)
# {"created_at": "2000-01-01T00:00:00", "age": 20, "name": "Foo"}

あるいはJSONEncoderを継承したクラスを作成する

json.dumpsにcls引数で変換に利用するクラスを変更できる(defaultではjson.JSONEncoderが使われる)
したがって、以下の様なJSONEncoderを継承したクラスを定義してclsに渡してもOK。

class DateTimeSupportJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()
        return super(DateTimeSupportJSONEncoder, self).default(o)

json.dumps(person, cls=DateTimeSupportJSONEncoder)
# {"created_at": "2000-01-01T00:00:00", "age": 20, "name": "Foo"}