Я использовал эту стратегию в прошлом и был ей очень доволен: закодируйте ваши пользовательские объекты как литералы объектов JSON (например, Python dict
s) со следующей структурой:
{ '__ClassName__': { ... } }
Этопо сути, это один элемент dict
, единственный ключ которого является специальной строкой, которая указывает, какой тип объекта кодируется, и значение которого равно dict
атрибутов экземпляра.Если это имеет смысл.
Очень простая реализация кодера и декодера (упрощенная из кода, который я фактически использовал) выглядит примерно так:
TYPES = { 'ParentClass': ParentClass,
'ChildClass': ChildClass }
class CustomTypeEncoder(json.JSONEncoder):
"""A custom JSONEncoder class that knows how to encode core custom
objects.
Custom objects are encoded as JSON object literals (ie, dicts) with
one key, '__TypeName__' where 'TypeName' is the actual name of the
type to which the object belongs. That single key maps to another
object literal which is just the __dict__ of the object encoded."""
def default(self, obj):
if isinstance(obj, TYPES.values()):
key = '__%s__' % obj.__class__.__name__
return { key: obj.__dict__ }
return json.JSONEncoder.default(self, obj)
def CustomTypeDecoder(dct):
if len(dct) == 1:
type_name, value = dct.items()[0]
type_name = type_name.strip('_')
if type_name in TYPES:
return TYPES[type_name].from_dict(value)
return dct
В этой реализации предполагается, чтообъекты, которые вы кодируете, будут иметь метод класса from_dict()
, который знает, как создать экземпляр из dict
, декодированного из JSON.
Кодер и декодер легко расширять для поддержки пользовательских типов (например,datetime
объекты).
РЕДАКТИРОВАТЬ , чтобы ответить на ваши изменения: Хорошая особенность такой реализации в том, что она автоматически кодирует и декодирует экземпляры любого объекта, найденного в TYPES
картографирование.Это означает, что он будет автоматически обрабатывать дочерний класс следующим образом:
class ChildClass(object):
def __init__(self):
self.foo = 'foo'
self.bar = 1.1
self.parent = ParentClass(1)
Это должно привести к JSON что-то вроде следующего:
{ '__ChildClass__': {
'bar': 1.1,
'foo': 'foo',
'parent': {
'__ParentClass__': {
'foo': 1}
}
}
}