How to change json encoding behaviour for serializable python object?

前端 未结 13 1224
无人及你
无人及你 2020-12-02 09:47

It is easy to change the format of an object which is not JSON serializable eg datetime.datetime.

My requirement, for debugging purposes, is to alter the way some cu

13条回答
  •  执笔经年
    2020-12-02 10:20

    If you are able to change the way json.dumps is called. You can do all the processing required before the JSON encoder gets his hands on it. This version does not use any kind of copying and will edit the structures in-place. You can add copy() if required.

    import datetime
    import json
    import collections
    
    
    def json_debug_handler(obj):
        print("object received:")
        print type(obj)
        print("\n\n")
        if isinstance(obj, collections.Mapping):
            for key, value in obj.iteritems():
                if isinstance(value, (collections.Mapping, collections.MutableSequence)):
                    value = json_debug_handler(value)
    
                obj[key] = convert(value)
        elif isinstance(obj, collections.MutableSequence):
            for index, value in enumerate(obj):
                if isinstance(value, (collections.Mapping, collections.MutableSequence)):
                    value = json_debug_handler(value)
    
                obj[index] = convert(value)
        return obj
    
    def convert(obj):
        if  isinstance(obj, datetime.datetime):
            return obj.isoformat()
        elif isinstance(obj,mDict):
            return {'orig':obj , 'attrs': vars(obj)}
        elif isinstance(obj,mList):
            return {'orig':obj, 'attrs': vars(obj)}
        else:
            return obj
    
    
    class mDict(dict):
        pass
    
    
    class mList(list):
        pass
    
    
    def test_debug_json():
        games = mList(['mario','contra','tetris'])
        games.src = 'console'
        scores = mDict({'dp':10,'pk':45})
        scores.processed = "qunprocessed"
        test_json = { 'games' : games , 'scores' : scores , 'date': datetime.datetime.now() }
        print(json.dumps(json_debug_handler(test_json)))
    
    if __name__ == '__main__':
        test_debug_json()
    

    You call json_debug_handler on the object you are serializing before passing it to the json.dumps. With this pattern you could also easily reverse the changes and/or add extra conversion rules.

    edit:

    If you can't change how json.dumps is called, you can always monkeypatch it to do what you want. Such as doing this:

    json.dumps = lambda obj, *args, **kwargs: json.dumps(json_debug_handler(obj), *args, **kwargs)
    

提交回复
热议问题