Puhhh.... hier mein zweiter Entwurf:
Code: Alles auswählen
JSON_STANDARD_TYPES = [
dict,
list, tuple,
str, unicode,
int, long, float,
bool,
type(None)
]
def deserialize_object(o):
if o is not None and '__type' in o:
typename = o.pop('__type')
value = o.get('__value', o.iteritems())
modulename, classname = typename.rsplit('.', 1)
#TODO: load module dynamically depending on python-version
#module = importlib.import_module(modulename)
module = __import__(modulename, fromlist=[classname])
cls = getattr(module, classname, None)
if cls in JSON_STANDARD_TYPES or cls == set:
return cls(value)
elif classname == 'datetime':
return cls.strptime(value, '%Y%m%d%H%M')
elif classname == 'date':
return cls(*value)
elif cls is None:
return
else:
cls = cls.__new__(cls)
if hasattr(cls, '__setstate__'):
cls.__setstate__(o)
else:
for attr, value in value:
cls.__dict__[attr] = deserialize_object(value)
return cls
else:
return o
def default(obj):
objtype = type(obj)
objname = objtype.__name__
objmodule = objtype.__module__
typename = objmodule + '.' + objname
state = {'__type': typename}
if objtype in JSON_STANDARD_TYPES:
state['__value'] = obj
elif objtype == set:
state['__value'] = list(obj)
elif objname == 'date':
state['__value'] = (obj.year, obj.month, obj.day)
elif objname == 'datetime':
state['__value'] = obj.strftime('%Y%m%d%H%M')
else:
if hasattr(obj, '__getstate__'):
attrs = obj.__getstate__()
else:
attrs = dict(obj.__dict__)
for attr, value in attrs.iteritems():
state[attr] = default(value)
return state
Nicht ganz so glücklich bin ich darüber, dass mit dieser Lösung manche Objekte 2 mal an 'deserialize_object()' geschickt werden:
Einmal, wenn sie tatsächlich deserialisiert werden und evtl. nochmal, wenn sie innerhalb der 'for'-Schleife einer Klasse als Attribut hinzugefügt werden. Nachdem ich unter Python < 2.7 keinen Einfluss darauf habe, in welcher Reihenfolge das an 'json.load()' dict abgearbeitet wird, wüsste ich nicht, wie sich das lösen lässt.
Ich könnte natürlich einfach alle JSON_STANDARD_TYPES in 'default()' unverändert durchwinken, dann allerdings würden non-JSON_STANDARD_TYPES die sich z. B. in einer Liste befinden nicht deserialisiert, da sie ja von 'json.load()' nie an 'deserialize_object()' übergeben werden.
Was meint ihr?
mutetella