В прошлом посте мы научили JSON понимать новый тип данных. Но что если придётся записывать в JSON много разных неподдерживаемых типов?
Описывать для каждого отдельный if isinstance()?
А если нам не известно что именно придётся сериализовать и нужно поддерживать в принципе всё что угодно? Ну хотя бы как-то записать объект чтобы не было ошибки и чтобы объект записался в JSON более менее информативно.
В этом случае можно вызвать стандартные способы репрезентации объекта. Самое простое это функция repr(). И тут уж как повезёт с тем, как именно разработчик позаботился о таком поведении его класса.
Более описательный метод, это закинуть объект в словарь с именем класса и данными инстанса.
В общем, возвращаясь к примеру из прошлого поста, мы просто убираем проверку конкретного типа
class MySerializer(json.JSONEncoder):
def default(self, obj):
return {'type': obj.__class__.__name__,
'data': vars(obj)}
Функция vars() аналогична обращению к атрибуту __dict__
Теперь любой ранее неизвестный объект будет успешно сериализован... или нет?
>>> json.dumps(datetime.datetime.now(), cls=MySerializer)
AttributeError: 'datetime.datetime' object has no attribute '__dict__
Так уж вышло, что не любой объект имеет атрибут __dict__. В таком случае используем repr()
class MySerializer(json.JSONEncoder):
def default(self, obj):
return {'type': obj.__class__.__name__,
'data': getattr(obj, '__dict__', repr(obj))}
То есть мы пробуем забрать данные инстанса, и если не получается то вызываем стандартное строковое представление объекта в надежде что разработчики позаботились о нём.
>>> json.dumps(datetime.now(), cls=MySerializer)
'{"type": "datetime", "data": "datetime.datetime(...)"}'
⚠️ PS: Не могу сказать что решение идеально. Такую неявную сериализацию можно сравнить с замалчиванием ошибок.
try:
do_something()
except:
pass
То есть в какой-то момент вы будете получать совершенно бесполезные данные и придётся искать где это происходит. Если не определён метод __repr__ то вы получите что-то вроде такого
<__main__.MyClass object at 0x00000147CE48CBC8>
Что с этим делать? Непонятно! 🤔
Скорее всего найдутся люди, которые осудят такой подход.
Может выбрасывать ошибку в случае отсутствия метода __repr__ в классе?
#libs#tricks