#python #json #python-3.x #enums
Вопрос:
Если я напишу
import json
class Color():
FUSCHIA = 0x00
TURQUOISE = 0x01
EMERALD = 0x02
def my_default_serializer(o):
return o.__dict__
def get_colors():
return json.dumps(
{
'dark_bg': True,
'colors_batch': [Color.TURQUOISE,
Color.EMERALD]
},
default=my_default_serializer
)
print(get_colors())
тогда я получу, как и ожидалось:
{"dark_bg": true, "colors_batch": [1, 2]}
Теперь предположим, что я модернизировал этот код, введя enum.Enum
. Помимо прочего, это удобно, потому Enum
что будет анализировать строку (например, считывать из файла), и поэтому я заменяю приведенный выше код на:
import json
from enum import Enum
class Color(Enum):
FUSCHIA = 0x00
TURQUOISE = 0x01
EMERALD = 0x02
def my_default_serializer(o):
return o.__dict__
def get_colors():
return json.dumps(
{
'dark_bg': True,
'colors_batch': [Color['TURQUOISE'],
Color['EMERALD']]
},
default=my_default_serializer
)
print(get_colors())
Это приводит к ошибке:
AttributeError: 'mappingproxy' object has no attribute '__dict__'
(и если я не укажу сериализатор по умолчанию, я получу TypeError: Object of type 'Color' is not JSON serializable
).
Как я должен JSON-сериализовать дочерние элементы перечисления?
Комментарии:
1. можете ли вы поделиться определением
big_obj
? почемуmy_default_serializer
используется?2. @balderman Спасибо, что спросил. Теперь я заменил вопрос на идентичный с автономным примером, иллюстрирующим проблему.
3. Мне удалось сериализовать
Color
. Смотреть ниже
Ответ №1:
смотрите ниже — кажется, работает. Идея состоит в том , чтобы переопределить default
метод of JSONEncoder
, проверить, является ли входящий аргумент экземпляром a Color
, и обработать его.
import json
from enum import Enum
class Color(Enum):
FUSCHIA = 0x00
TURQUOISE = 0x01
EMERALD = 0x02
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Enum):
return {"__enum__": str(obj)}
return json.JSONEncoder.default(self, obj)
def get_colors():
return json.dumps(
{
'dark_bg': True,
'colors_batch': [Color['TURQUOISE'],
Color['EMERALD']]
}, cls=EnumEncoder
)
print(get_colors())
Комментарии:
1. Ваш код работает только для перечисления
Color
-можете ли вы заставить его работать для любого перечисления?2. @EthanFurman — Добавлена любая поддержка перечисления.
3. Вот и все. Только один комментарий: теперь мы получаем
{"dark_bg": true, "colors_batch": [{"__enum__": "Color.TURQUOISE"}, {"__enum__": "Color.EMERALD"}]}
вместо{"dark_bg": true, "colors_batch": [1, 2]}
. Чтобы сохранить вывод без изменений (чтобы нам не пришлось изменять «другую сторону», заменитеreturn {"__enum__": str(obj)}
наreturn obj.value
.