How to change json encoding behaviour for serializable python object?

前端 未结 13 1235
无人及你
无人及你 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:13

    If you are only looking for serialization and not deserialization then you can process the object before sending it to json.dumps. See below example

    import datetime
    import json
    
    
    def is_inherited_from(obj, objtype):
        return isinstance(obj, objtype) and not type(obj).__mro__[0] == objtype
    
    
    def process_object(data):
        if isinstance(data, list):
            if is_inherited_from(data, list):
                return process_object({"orig": list(data), "attrs": vars(data)})
            new_data = []
            for d in data:
                new_data.append(process_object(d))
        elif isinstance(data, tuple):
            if is_inherited_from(data, tuple):
                return process_object({"orig": tuple(data), "attrs": vars(data)})
            new_data = []
            for d in data:
                new_data.append(process_object(d))
            return tuple(new_data)
        elif isinstance(data, dict):
            if is_inherited_from(data, dict):
                return process_object({"orig": list(data), "attrs": vars(data)})
            new_data = {}
            for k, v in data.items():
                new_data[k] = process_object(v)
        else:
            return data
        return new_data
    
    
    def json_debug_handler(obj):
        print("object received:")
        print("\n\n")
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
    
    
    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 = "unprocessed"
        test_json = {'games': games, 'scores': scores, 'date': datetime.datetime.now()}
        new_object = process_object(test_json)
        print(json.dumps(new_object, default=json_debug_handler))
    
    
    if __name__ == '__main__':
        test_debug_json()
    

    The output of the same is

    {"games": {"orig": ["mario", "contra", "tetris"], "attrs": {"src": "console"}}, "scores": {"orig": ["dp", "pk"], "attrs": {"processed": "unprocessed"}}, "date": "2018-01-24T12:59:36.581689"}

    It is also possible to override the JSONEncoder, but since it uses nested methods, it would be complex and require techniques discussed in below

    Can you patch *just* a nested function with closure, or must the whole outer function be repeated?

    Since you want to keep things simple, I would not suggest going that route

提交回复
热议问题