Si desea codificar un enum.Enummiembro arbitrario en JSON y luego decodificarlo como el mismo miembro de enumeración (en lugar de simplemente el valueatributo del miembro de enumeración ), puede hacerlo escribiendo una JSONEncoderclase personalizada y una función de decodificación para pasar como object_hookargumento json.load()ao 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
La as_enumfunción se basa en que el JSON se haya codificado usando EnumEncoder, o algo que se comporte de manera idéntica.
La restricción a los miembros de PUBLIC_ENUMSes necesaria para evitar que se utilice un texto creado con fines malintencionados para, por ejemplo, engañar al código de llamada para que guarde información privada (por ejemplo, una clave secreta utilizada por la aplicación) en un campo de base de datos no relacionado, desde donde podría quedar expuesto. (ver http://chat.stackoverflow.com/transcript/message/35999686#35999686 ).
Uso de ejemplo:
>>> 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'}
if isinstance(obj, Enum):?Sé que esto es antiguo, pero creo que ayudará a la gente. Acabo de pasar por este problema exacto y descubrí que si está usando enumeraciones de cadena, declarar sus enumeraciones como una subclase de
strfunciona bien para casi todas las situaciones: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'))Saldrá:
LogLevel.DEBUG "DEBUG" DEBUG LogLevel.DEBUGComo puede ver, al cargar JSON se genera la cadena,
DEBUGpero se puede convertir fácilmente en un objeto LogLevel. Una buena opción si no desea crear un JSONEncoder personalizado.fuente
class LogLevel(str, Enum): DEBUG = 'Дебаг' INFO = 'Инфо'en este casoenum with strno funciona correctamente (La respuesta correcta depende de lo que pretenda hacer con la versión serializada.
Si va a anular la serialización de nuevo en Python, consulte la respuesta de Zero .
Si su versión serializada va a otro idioma, probablemente desee usar un
IntEnumen su lugar, que se serializa automáticamente como el número entero correspondiente:from enum import IntEnum import json class Status(IntEnum): success = 0 failure = 1 json.dumps(Status.success)y esto devuelve:
'0'fuente
Python3.4, y esta respuesta es 3.4+ específica.EnumMetalugar deIntEnumEnum, posiblemente con unstrmixin -class MyStrEnum(str, Enum): ...EnumMeta, lo que estaba destinado a ser una metaclase únicamente. En su lugar, tenga en cuenta que la implementación deIntEnumes de una sola línea y puede lograr lo mismo parastrconclass StrEnum(str, Enum): ....En Python 3.7, solo puede usar
json.dumps(enum_obj, default=str)fuente
nameenumeración de en la cadena json. La mejor forma será utilizarvaluela enumeración.json.dumps(enum_obj, default=lambda x: x.value)Me gustó la respuesta de Zero Piraeus, pero la modifiqué ligeramente para trabajar con la API para Amazon Web Services (AWS) conocida como Boto.
class EnumEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Enum): return obj.name return json.JSONEncoder.default(self, obj)Luego agregué este método a mi modelo de datos:
def ToJson(self) -> str: return json.dumps(self.__dict__, cls=EnumEncoder, indent=1, sort_keys=True)Espero que esto ayude a alguien.
fuente
ToJsona su modelo de datos?Si está utilizando
jsonpicklela forma más sencilla debería verse como a continuación.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)Después de la serialización de Json, tendrá lo esperado en
{"status": 0}lugar de{"status": {"__objclass__": {"py/type": "__main__.Status"}, "_name_": "success", "_value_": 0}}fuente
Esto funcionó para mí:
class Status(Enum): success = 0 def __json__(self): return self.valueNo tuve que cambiar nada más. Obviamente, solo obtendrá el valor de esto y tendrá que hacer algún otro trabajo si desea convertir el valor serializado nuevamente en la enumeración más adelante.
fuente
JSONEncoderalguna parte?