オブジェクトをjsonに変換しようとするとタイプエラーが発生したので記録
TypeError: Object of type SampleClass is not JSON serializable
原因
JSONへのエンコーダとしてはデフォルトでjson.JSONEncoder
を使用しており、変換の際の対応は以下になります。
Python | JSON |
---|---|
dict | object |
list,tuple | array |
int,float | number |
True | true |
False | false |
None | null |
つまり、ここにない型をエンコーディングしようとするとTypeErrorが出るというわけです
object, Enum, datetime型などをjsonにしようとした際に遭遇する問題でしょうか
import json
from datetime import date
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
class SampleClass:
def __init__(self, name):
self.name = name
# datetime
json.dumps(date.today()) # TypeError: Object of type date is not JSON serializable
# Enum
json.dumps(Color.RED) # TypeError: Object of type Color is not JSON serializable
# object
json.dumps(SampleClass("bob")) # TypeError: Object of type SampleClass is not JSON serializable
対応
JSONEncoder
クラスを拡張してデフォルト以外の型にも対応できるようにします。
サブクラスを用意し、default()メソッドをオーバーライドし、任意のオブジェクトを上記対応表の認識可能な型に変換します。
具体的には以下のようにJSONEndecoder
のサブクラスでdefault()
を実装し、デフォルト以外の型の場合にどのような変換を行うかを定義します。
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
# Enum -> str,int
if isinstance(obj, Enum):
return obj.value # or obj.name
# datetime -> str
if isinstance(obj, datetime):
return obj.isoformat() # https://docs.python.org/ja/3.7/library/datetime.html#datetime.datetime.isoformat
# object -> dict
elif isinstance(obj, object) and hasattr(obj, '__dict__'):
return obj.__dict__
# dict,str,int,... -> default
return super().default(obj)
これを使って先ほどの例を試します
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
class SampleClass:
def __init__(self, name: str, color: Color, created_at: datetime):
self.name = name
self.color = color
self.created_at = created_at
sample = SampleClass("bob", Color.RED, datetime.now())
sample_json = json.dumps(sample, cls=CustomJSONEncoder)
print(sample_json) # {"name": "bob", "color": 1, "created_at": "2024-07-12T14:34:53.927615"}
無事にシリアライズできるようになりました。
ref : https://docs.python.org/ja/3/library/json.html#module-json