Если вы хотите закодировать произвольный 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'}
if isinstance(obj, Enum):
?Я знаю, что это устарело, но чувствую, что это поможет людям. Я только что рассмотрел эту точную проблему и обнаружил, что если вы используете перечисления строк, объявление перечислений как подкласса
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.источник
class LogLevel(str, Enum): DEBUG = 'Дебаг' INFO = 'Инфо'
в этом случаеenum with str
не работает должным образом (Правильный ответ зависит от того, что вы собираетесь делать с сериализованной версией.
Если вы собираетесь выполнить десериализацию обратно в Python, см . Ответ Zero .
Если ваша сериализованная версия будет переведена на другой язык, вы, вероятно, захотите использовать
IntEnum
вместо нее , которая автоматически сериализуется как соответствующее целое число:from enum import IntEnum import json class Status(IntEnum): success = 0 failure = 1 json.dumps(Status.success)
и это возвращается:
'0'
источник
Python3.4
, и этот ответ специфичен для 3.4+.EnumMeta
вместоIntEnum
Enum
, возможно, сstr
миксином -class MyStrEnum(str, Enum): ...
EnumMeta
, который был задуман только как метакласс. Вместо этого обратите внимание, что реализацияIntEnum
является однострочным, и вы можете добиться того же дляstr
withclass StrEnum(str, Enum): ...
.В Python 3.7 можно просто использовать
json.dumps(enum_obj, default=str)
источник
name
enum в строку json. Лучше всего использоватьvalue
перечисление.json.dumps(enum_obj, default=lambda x: x.value)
Мне понравился ответ Zero Piraeus, но он немного изменил его для работы с API для Amazon Web Services (AWS), известным как Boto.
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)
Я надеюсь, что это помогает кому-то.
источник
ToJson
в вашу модель данных?Если вы используете
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
Больше ничего менять не пришлось. Очевидно, вы получите только значение из этого, и вам нужно будет проделать некоторую другую работу, если вы захотите позже преобразовать сериализованное значение обратно в перечисление.
источник
JSONEncoder
где-то есть собственный ?