Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
103
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@podhmo

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

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"}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
103
Help us understand the problem. What are the problem?