Можно ли переопределить сериализатор JSONEncoder для стандартных типов?
Можно ли как-нибудь переопределить поведение JSONEncoder для стандартных типов? Например, хочу, чтобы словарь сериализовывался не через {}, а через <>, чтобы строки не были обёрнуты в " и т.д. Причём, как-то особенно обрабатывать необходимо только некоторые из стандартных типов
Например, код:
import json
print(json.dumps({"a": "5", "b": {"c": "d", "e": "f", "g": ["1", "2", 3]}}, indent=4))
Вывод:
{
"a": "5",
"b": {
"c": "d",
"e": "f",
"g": [
"1",
"2",
3
]
}
}
Я же хочу получить:
<
a: 5,
b: <
c: d,
e: f,
g: [
1,
2,
3
]
>
>
Необходимо получить данные именно в "кастомном" виде, десериализация не нужна.
Находил, как можно добавить сериализацию нестандартных типов, но как поменять поведение именно для стандартных типов (
dict, list, str, int, float, True, False, None) не нашёл.
Ответы (1 шт):
Автор решения: Михаил Муругов
Мой, очень костыльный вариант:
Вывод:
Для моей задачи работает очень даже хорошо, но будет беда с отступами, если в сериализуемом объекте где-нибудь будет список.
→ Ссылка
Разобрался. Переопределять надо было методы encode и iterencode класса JSONEncoder.
Мой, очень костыльный вариант:
import json
class CustomEncoder(json.JSONEncoder): # Определяем собственный кодировщик
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.current_level = 0 # Текущий уровень отступа
def encode(self, o): # Как я понял, правило кодирования типов, кроме list и dict
if isinstance(o, str): # Наше правило кодирования строки
return o # Не оборачиваем в "
else: # Иначе кодируем правилом по умолчанию
return super().encode(o)
def iterencode(self, o, _one_shot=False): # Правило кодирования list и dict
if isinstance(o, dict): # Наше правило кодирования словаря
yield "<\n" # Начинаем сериализацию словаря с <
self.current_level += 1 # Увеличиваем текущий уровень отступа
for key, val in o.items():
yield "{indent}{key}{key_separator}{value}{item_separator}\n".format(
indent=" " * self.indent * self.current_level, # Вычисляем отступ
key=self.encode(key), # Кодируем ключ словаря по нашему правилу
key_separator=self.key_separator,
value=self.encode(val), # Кодируем значение по ключу по нашему правилу
item_separator=self.item_separator
)
self.current_level -= 1
yield "{indent}>".format( # Делаем отступ и
indent=" " * self.indent * self.current_level. # Закрываем словарь символом >
)
else:
yield from super().iterencode(o)
mydict = {
"a": "5",
"b": {
"c": "d",
"e": "f",
"g": {
"1": "one",
"2": "two",
}
}
}
print(json.dumps(
obj=mydict, # Что сериализуем
cls=CustomEncoder, # Кастомный кодировщик
indent=4, # Количество пробелов в отступе
))
Вывод:
<
a: 5,
b: <
c: d,
e: f,
g: <
1: one,
2: two,
>,
>,
>
Для моей задачи работает очень даже хорошо, но будет беда с отступами, если в сериализуемом объекте где-нибудь будет список.