Python json encoding with classes that need custom encoders but which may themselves have nested data structures -
this simplified version of trying ... let's have
class x(object): pass x = x() y = x() x.val = {1:2,3:4} y.val = {1:2,3:x}
how write custom json encoder recurses through encoding loop naturally ? not need json demonstrate class of type x, (a dot dict fine). actual example of may have data structures nested 10 deep.
obviously override default() method, not seem allow recursive calls - ie best have mess (and need json.loads otherwise thing gets double quoted / escaped):
class xencoder(json.jsonencoder): def default(self, obj): if isinstance(obj, x): return json.loads(self.encode({x:getattr(obj,x) x in dir(obj) if "__" not in x})) return json.jsonencoder.default(self, obj)
maybe on kill used used mixin class follow:
def _default_json_encoder(obj): """ default encoder, encountered must have to_dict method serialized. """ if hasattr(obj, "to_dict"): return obj.to_dict() else: raise typeerror('object of type %s value of %s not json serializable' % (type(obj), repr(obj))) class mixinjsonable(object): """ mixin pattern add capability object jsonable. if object have to_dict method used produce dict, otherwise mixinjsonable.to_dict used. "public" attributes dump , instance of self._jsonable tuple. attributes ignored passing ignored_keys parameter to_json method. _ignored_json_keys (class attribute) update , spread on class using mixin. """ # _ignored_json_keys = list() def to_dict(self): """ to_dict method dump public attributes. """ self._jsonable = (int, list, str, dict) _dict = dict() attr in dir(self): value = getattr(self, attr) if attr.startswith("_") or attr in getattr(mixinjsonable, "_ignored_json_keys", []): continue elif isinstance(value, self._jsonable) or value none or hasattr(value, 'to_dict'): # to_dict method used serialization method. value = value else: continue _dict[attr] = value return _dict def to_json(self, **kw): """ dump object json. accept same keys :func json.dumps:. if ignored_keys (list) passed, keys not dumped in json (filter on sons) """ indent = kw.pop("indent", 4) # use indent key if passed otherwise 4. _ignored_json_keys = kw.pop("ignored_keys", []) if _ignored_json_keys: mixinjsonable._ignored_json_keys = _ignored_json_keys return json.dumps(self, indent=indent, default=_default_json_encoder, **kw) class x(mixinjsonable): pass x = x() y = x() setattr(x,"val",{1:2,3:4}) setattr(y,"val",{1:2,3:x}) y.to_json()
will print:
{ "val": { "1": 2, "3": { "val": { "1": 2, "3": 4 } } } }
Comments
Post a Comment