Si desea codificar un enum.Enum
miembro arbitrario en JSON y luego decodificarlo como el mismo miembro de enumeración (en lugar de simplemente el value
atributo del miembro de enumeración ), puede hacerlo escribiendo una JSONEncoder
clase personalizada y una función de decodificación para pasar como object_hook
argumento 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_enum
funció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_ENUMS
es 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
str
funciona 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.DEBUG
Como puede ver, al cargar JSON se genera la cadena,
DEBUG
pero 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 str
no 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
IntEnum
en 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.EnumMeta
lugar deIntEnum
Enum
, posiblemente con unstr
mixin -class MyStrEnum(str, Enum): ...
EnumMeta
, lo que estaba destinado a ser una metaclase únicamente. En su lugar, tenga en cuenta que la implementación deIntEnum
es de una sola línea y puede lograr lo mismo parastr
conclass StrEnum(str, Enum): ...
.En Python 3.7, solo puede usar
json.dumps(enum_obj, default=str)
fuente
name
enumeración de en la cadena json. La mejor forma será utilizarvalue
la 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
ToJson
a su modelo de datos?Si está utilizando
jsonpickle
la 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.value
No 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
JSONEncoder
alguna parte?