How to change json encoding behaviour for serializable python object?

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

    If you define these to override __instancecheck__:

    def strict_check(builtin):
        '''creates a new class from the builtin whose instance check
        method can be overridden to renounce particular types'''
        class BuiltIn(type):
            def __instancecheck__(self, other):
                print 'instance', self, type(other), other
                if type(other) in strict_check.blacklist:
                    return False
                return builtin.__instancecheck__(other)
        # construct a class, whose instance check method is known.
        return BuiltIn('strict_%s' % builtin.__name__, (builtin,), dict())
    
    # for safety, define it here.
    strict_check.blacklist = ()
    

    then patch json.encoder like this to override _make_iterencode.func_defaults:

    # modify json encoder to use some new list/dict attr.
    import json.encoder
    # save old stuff, never know when you need it.
    old_defaults = json.encoder._make_iterencode.func_defaults
    old_encoder = json.encoder.c_make_encoder
    encoder_defaults = list(json.encoder._make_iterencode.func_defaults)
    for index, default in enumerate(encoder_defaults):
        if default in (list, dict):
            encoder_defaults[index] = strict_check(default)
    
    # change the defaults for _make_iterencode.
    json.encoder._make_iterencode.func_defaults = tuple(encoder_defaults)
    # disable C extension.
    json.encoder.c_make_encoder = None
    

    ... your example would almost work verbatim:

    import datetime
    import json
    
    def json_debug_handler(obj):
        print("object received:")
        print type(obj)
        print("\n\n")
        if  isinstance(obj, datetime.datetime):
            return obj.isoformat()
        elif isinstance(obj,mDict):
            # degrade obj to more primitive dict()
            # to avoid cycles in the encoding.
            return {'orig': dict(obj) , 'attrs': vars(obj)}
        elif isinstance(obj,mList):
            # degrade obj to more primitive list()
            # to avoid cycles in the encoding.
            return {'orig': list(obj), 'attrs': vars(obj)}
        else:
            return None
    
    
    class mDict(dict):
        pass
    
    
    class mList(list):
        pass
    
    # set the stuff we want to process differently.
    strict_check.blacklist = (mDict, mList)
    
    def test_debug_json():
        global test_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() }
        print(json.dumps(test_json,default=json_debug_handler))
    
    if __name__ == '__main__':
        test_debug_json()
    

    The things I needed to change were to make sure there were no cycles:

        elif isinstance(obj,mDict):
            # degrade obj to more primitive dict()
            # to avoid cycles in the encoding.
            return {'orig': dict(obj) , 'attrs': vars(obj)}
        elif isinstance(obj,mList):
            # degrade obj to more primitive list()
            # to avoid cycles in the encoding.
            return {'orig': list(obj), 'attrs': vars(obj)}
    

    and add this somewhere before test_debug_json:

    # set the stuff we want to process differently.
    strict_check.blacklist = (mDict, mList)
    

    here is my console output:

    >>> test_debug_json()
    instance <class '__main__.strict_list'> <type 'dict'> {'date': datetime.datetime(2013, 7, 17, 12, 4, 40, 950637), 'games': ['mario', 'contra', 'tetris'], 'scores': {'pk': 45, 'dp': 10}}
    instance <class '__main__.strict_dict'> <type 'dict'> {'date': datetime.datetime(2013, 7, 17, 12, 4, 40, 950637), 'games': ['mario', 'contra', 'tetris'], 'scores': {'pk': 45, 'dp': 10}}
    instance <class '__main__.strict_list'> <type 'datetime.datetime'> 2013-07-17 12:04:40.950637
    instance <class '__main__.strict_dict'> <type 'datetime.datetime'> 2013-07-17 12:04:40.950637
    instance <class '__main__.strict_list'> <type 'datetime.datetime'> 2013-07-17 12:04:40.950637
    instance <class '__main__.strict_dict'> <type 'datetime.datetime'> 2013-07-17 12:04:40.950637
    object received:
    <type 'datetime.datetime'>
    
    
    
    instance <class '__main__.strict_list'> <class '__main__.mList'> ['mario', 'contra', 'tetris']
    instance <class '__main__.strict_dict'> <class '__main__.mList'> ['mario', 'contra', 'tetris']
    instance <class '__main__.strict_list'> <class '__main__.mList'> ['mario', 'contra', 'tetris']
    instance <class '__main__.strict_dict'> <class '__main__.mList'> ['mario', 'contra', 'tetris']
    object received:
    <class '__main__.mList'>
    
    
    
    instance <class '__main__.strict_list'> <type 'dict'> {'attrs': {'src': 'console'}, 'orig': ['mario', 'contra', 'tetris']}
    instance <class '__main__.strict_dict'> <type 'dict'> {'attrs': {'src': 'console'}, 'orig': ['mario', 'contra', 'tetris']}
    instance <class '__main__.strict_list'> <type 'dict'> {'src': 'console'}
    instance <class '__main__.strict_dict'> <type 'dict'> {'src': 'console'}
    instance <class '__main__.strict_list'> <type 'list'> ['mario', 'contra', 'tetris']
    instance <class '__main__.strict_list'> <class '__main__.mDict'> {'pk': 45, 'dp': 10}
    instance <class '__main__.strict_dict'> <class '__main__.mDict'> {'pk': 45, 'dp': 10}
    instance <class '__main__.strict_list'> <class '__main__.mDict'> {'pk': 45, 'dp': 10}
    instance <class '__main__.strict_dict'> <class '__main__.mDict'> {'pk': 45, 'dp': 10}
    object received:
    <class '__main__.mDict'>
    
    
    
    instance <class '__main__.strict_list'> <type 'dict'> {'attrs': {'processed': 'unprocessed'}, 'orig': {'pk': 45, 'dp': 10}}
    instance <class '__main__.strict_dict'> <type 'dict'> {'attrs': {'processed': 'unprocessed'}, 'orig': {'pk': 45, 'dp': 10}}
    instance <class '__main__.strict_list'> <type 'dict'> {'processed': 'unprocessed'}
    instance <class '__main__.strict_dict'> <type 'dict'> {'processed': 'unprocessed'}
    instance <class '__main__.strict_list'> <type 'dict'> {'pk': 45, 'dp': 10}
    instance <class '__main__.strict_dict'> <type 'dict'> {'pk': 45, 'dp': 10}
    {"date": "2013-07-17T12:04:40.950637", "games": {"attrs": {"src": "console"}, "orig": ["mario", "contra", "tetris"]}, "scores": {"attrs": {"processed": "unprocessed"}, "orig": {"pk": 45, "dp": 10}}}
    
    0 讨论(0)
提交回复
热议问题