前置き
Pythonの標準ライブラリjson.dump
は、辞書型のオブジェクトの内容をそのまま保存でき、仕事でも重宝しています。
しかし難点があって、扱えるのは
- 数値型
- 文字列型
- リスト型
- 辞書型
といった基本型のオブジェクトだけであり、datetimeオブジェクトなど時刻の情報をJSONファイルに保存するときは
record_time = datetime.now()
obj = {
'RecordTime': record_time.strftime('%Y%m%d-%H%M%S')
}
...
のように一度文字列に変換しないといけないし、
JSONファイルからdatetimeオブジェクトを生成するときも
obj['RecordTime'] = datetime.strptime(obj['RecordTime'], '%Y%m%d-%H%M%S')
っていちいち変換しないといけないし、不便だなぁ。
そう思っていた時期が、僕にもありました。
そんなあなたにJSONEncoder
そんなある日、jsonモジュールのドキュメントを眺めていたら、見つけました。
これを使えば、datetimeなどのオブジェクトと、文字列や数値との変換をjson.dump
を実行する時に同時に実行してくれるそうです。
たとえば、
record = {
"singleTimestamp": datetime.datetime(2019, 1, 29, 19, 29, 2, 234680),
"listedTimestamps": [
datetime.datetime(2019, 1, 29, 19, 57, 2, 234693),
datetime.datetime(2019, 1, 29, 19, 47, 2, 234695),
datetime.datetime(2019, 1, 29, 19, 37, 2, 234697)
],
"nested": {
"timestamp": datetime.datetime(2019, 1, 29, 19, 31, 2, 234689)
}
こんなデータをJSONに保存したいと思ったら、
from json import JSONEncoder
class DatetimeJSONEncoder(JSONEncoder): # JSONEncoderを継承させる
def default(self, o):
if type(o).__name__ == 'datetime': # 値がdatetime型だったら、
return o.strftime('%Y%m%d-%H%M%S') # 文字列に変換して返す
else:
return o
のようにJSONEncoder
を継承する形で新しいクラスを定義し、default()
メソッドに、エントリーのtypeとその変換の仕方を対応させて書いて、
with open('jsonencodertest.json', 'w') as fp:
json.dump(record, fp, indent=2, cls=DatetimeJSONEncoder)
と、cls
引数にそのクラスを指定してあげれば良いだけです。
最後に
やっぱドキュメント読むって大事ですね。