[python] Enum 멤버를 JSON으로 직렬화
Enum
결과 JSON을 다시 Python 객체로 역 직렬화 할 수 있도록 Python 멤버를 JSON으로 직렬화하려면 어떻게해야 합니까?
예를 들어 다음 코드는 다음과 같습니다.
from enum import Enum
import json
class Status(Enum):
success = 0
json.dumps(Status.success)
오류가 발생합니다.
TypeError: <Status.success: 0> is not JSON serializable
어떻게 피할 수 있습니까?
답변
임의의 enum.Enum
멤버를 JSON 으로 인코딩 한 다음 동일한 열거 형 멤버로 디코딩 하려는 경우 (단순히 열거 형 멤버의 value
속성이 아니라) 사용자 정의 JSONEncoder
클래스 를 작성하고 또는 object_hook
인수로 전달할 디코딩 함수를 작성하면 됩니다. :json.load()
json.loads()
PUBLIC_ENUMS = {
'Status': Status,
# ...
}
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if type(obj) in PUBLIC_ENUMS.values():
return {"__enum__": str(obj)}
return json.JSONEncoder.default(self, obj)
def as_enum(d):
if "__enum__" in d:
name, member = d["__enum__"].split(".")
return getattr(PUBLIC_ENUMS[name], member)
else:
return d
이 as_enum
함수는를 사용하여 인코딩 된 JSON EnumEncoder
또는 이와 동일하게 작동하는 무언가 에 의존 합니다.
의 구성원에 대한 제한 PUBLIC_ENUMS
은 악의적으로 제작 된 텍스트가 사용되는 것을 방지하기 위해 필요합니다. 예를 들어, 호출 코드를 속여 개인 정보 (예 : 응용 프로그램에서 사용하는 비밀 키)를 관련없는 데이터베이스 필드에 저장 한 다음 노출 될 수 있습니다. ( http://chat.stackoverflow.com/transcript/message/35999686#35999686 참조 ).
사용 예 :
>>> data = {
... "action": "frobnicate",
... "status": Status.success
... }
>>> text = json.dumps(data, cls=EnumEncoder)
>>> text
'{"status": {"__enum__": "Status.success"}, "action": "frobnicate"}'
>>> json.loads(text, object_hook=as_enum)
{'status': <Status.success: 0>, 'action': 'frobnicate'}
답변
나는 이것이 오래되었다는 것을 알고 있지만 이것이 사람들을 도울 것이라고 생각합니다. 나는 방금이 정확한 문제를 겪었고 문자열 열거 형을 사용하고 있는지 발견하여 열거 형 str
을 거의 모든 상황에서 잘 작동 하는 하위 클래스로 선언했습니다 .
import json
from enum import Enum
class LogLevel(str, Enum):
DEBUG = 'DEBUG'
INFO = 'INFO'
print(LogLevel.DEBUG)
print(json.dumps(LogLevel.DEBUG))
print(json.loads('"DEBUG"'))
print(LogLevel('DEBUG'))
출력 :
LogLevel.DEBUG
"DEBUG"
DEBUG
LogLevel.DEBUG
보시다시피 JSON을로드하면 문자열이 출력 DEBUG
되지만 LogLevel 개체로 쉽게 다시 캐스팅 할 수 있습니다. 사용자 지정 JSONEncoder를 생성하지 않으려는 경우 좋은 옵션입니다.
답변
정답은 직렬화 된 버전으로 수행하려는 작업에 따라 다릅니다.
Python으로 다시 직렬화 해제하려면 Zero ‘s answer를 참조하십시오 .
직렬화 된 버전이 다른 언어로 이동하는 경우 IntEnum
대신 해당 정수로 자동 직렬화되는를 사용할 수 있습니다 .
from enum import IntEnum
import json
class Status(IntEnum):
success = 0
failure = 1
json.dumps(Status.success)
그리고 이것은 다음을 반환합니다.
'0'
답변
Python 3.7에서는
json.dumps(enum_obj, default=str)
답변
Zero Piraeus의 답변을 좋아했지만 Boto로 알려진 Amazon Web Services (AWS) 용 API 작업을 위해 약간 수정했습니다.
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Enum):
return obj.name
return json.JSONEncoder.default(self, obj)
그런 다음이 메서드를 데이터 모델에 추가했습니다.
def ToJson(self) -> str:
return json.dumps(self.__dict__, cls=EnumEncoder, indent=1, sort_keys=True)
누군가에게 도움이되기를 바랍니다.
답변
jsonpickle
가장 쉬운 방법을 사용한다면 아래와 같이 보일 것입니다.
from enum import Enum
import jsonpickle
@jsonpickle.handlers.register(Enum, base=True)
class EnumHandler(jsonpickle.handlers.BaseHandler):
def flatten(self, obj, data):
return obj.value # Convert to json friendly format
if __name__ == '__main__':
class Status(Enum):
success = 0
error = 1
class SimpleClass:
pass
simple_class = SimpleClass()
simple_class.status = Status.success
json = jsonpickle.encode(simple_class, unpicklable=False)
print(json)
JSON 직렬화 한 후이 같은 예상 한 것 {"status": 0}
대신
{"status": {"__objclass__": {"py/type": "__main__.Status"}, "_name_": "success", "_value_": 0}}
답변
이것은 나를 위해 일했습니다.
class Status(Enum):
success = 0
def __json__(self):
return self.value
다른 것을 변경할 필요가 없습니다. 분명히이 값에서 값을 얻을 수 있으며 나중에 직렬화 된 값을 다시 열거 형으로 변환하려면 다른 작업을 수행해야합니다.