개요
데이터를 다루다 보면 딕셔너리 형식의 데이터를 JSON 형식으로 변환해야 하는 경우가 종종 있다. 이때 데이터에 큰 문제가 없어서 JSON 형식으로 잘 변환이 되면 좋지만, 아래처럼 오류가 나는 상황이 발생할 수도 있다.
import json
from datetime import datetime
data = {
'create_dt': datetime.now(),
'name': 'june',
'age': 22,
}
print(json.dumps(data))

내 경우에는 주로 날짜 형식 데이터를 변환하다가 발생하곤 하는데, 아주 간편하게 문제를 해결하는 방법을 적어둔다.
원인
TypeError: Object of type datetime is not JSON serializable
JSON은 문자열, 숫자, 배열, 객체와 같은 단순 유형만 직렬화할 수 있다. 다시 말해 datetime 객체는 JSON에서 지원하는 데이터 유형이 아니다. Python에서 제공하는 복합 객체이기 때문에 json.dumps가 바로 처리할 수 없다.
이 문제를 해결하려면 json.dumps가 내부적으로 datetime을 어떻게 처리할지 지정해주어야 한다.
해결
1. 직렬화되지 않는 객체를 문자열로 변환
json.dump, json.dumps 함수는 default라는 매개변수로 직렬화할 수 없는 객체에 대해 호출되는 함수를 전달할 수 있다. 개발자는 이 매개변수를 통해 직렬화되지 않는 객체를 어떻게 처리할 건지 지정할 수 있다.
가장 간편하게 해결하는 방법은 문자열 함수인 str을 지정하는 것이다.
import json
from datetime import datetime
data = {
'create_dt': datetime.now(),
'name': 'june',
'age': 22,
}
print(json.dumps(data, default=str))

2. 사용자 정의 인코더 사용
str 함수로 처리하기가 어렵다면 사용자 정의 인코더를 정의하여 default 매개변수로 전달하는 방법이 있다.
default 매개변수로 전달된 함수는 직렬화할 수 없는 객체에 대해 호출되므로, 해당 객체의 데이터 타입을 확인하여 처리하는 방식으로 구현하면 될 것 같다.
import json
from datetime import datetime, date
def json_default(obj):
# 사용자 정의 인코더
if isinstance(obj, (datetime, date)):
return obj.isoformat()
raise TypeError(repr(obj) + " is not JSON serializable")
data = {
'create_dt': datetime.now(),
'name': 'june',
'age': 22,
}
print(json.dumps(data, default=json_default))

참고 문서
https://docs.python.org/3/library/json.html#json.dump