How to change json encoding behaviour for serializable python object?

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

    Along the lines of FastTurtle's suggestion, but requiring somewhat less code and much deeper monkeying, you can override isinstance itself, globally. This is probably Not A Good Idea, and may well break something. But it does work, in that it produces your required output, and it's quite simple.

    First, before json is imported anywhere, monkey-patch the builtins module to replace isinstance with one that lies, just a little bit, and only in a specific context:

    _original_isinstance = isinstance
    
    def _isinstance(obj, class_or_tuple):
        if '_make_iterencode' in globals():
            if not _original_isinstance(class_or_tuple, tuple):
                class_or_tuple = (class_or_tuple,)
            for custom in mList, mDict:
                if _original_isinstance(obj, custom):
                    return custom in class_or_tuple
        return _original_isinstance(obj, class_or_tuple)
    
    try:
        import builtins # Python 3
    except ImportError:
        import __builtin__ as builtins # Python 2
    builtins.isinstance = _isinstance
    

    Then, create your custom encoder, implementing your custom serialization and forcing the use of _make_iterencode (since the c version won't be affected by the monkeypatching):

    class CustomEncoder(json.JSONEncoder):
        def iterencode(self, o, _one_shot = False):
            return super(CustomEncoder, self).iterencode(o, _one_shot=False)
    
        def default(self, obj):
            if isinstance(obj, datetime.datetime):
                return obj.isoformat()
            elif isinstance(obj,mDict):
                return {'orig':dict(obj) , 'attrs': vars(obj)}
            elif isinstance(obj,mList):
                return {'orig':list(obj), 'attrs': vars(obj)}
            else:
                return None
    

    And that's really all there is to it! Output from Python 3 and Python 2 below.

    Python 3.6.3 (default, Oct 10 2017, 21:06:48)
    ...
    >>> from test import test_debug_json
    >>> test_debug_json()
    {"games": {"orig": ["mario", "contra", "tetris"], "attrs": {"src": "console"}}, "scores": {"orig": {"dp": 10, "pk": 45}, "attrs": {"processed": "unprocessed"}}, "date": "2018-01-27T13:56:15.666655"}
    
    Python 2.7.13 (default, May  9 2017, 12:06:13)
    ...
    >>> from test import test_debug_json
    >>> test_debug_json()
    {"date": "2018-01-27T13:57:04.681664", "games": {"attrs": {"src": "console"}, "orig": ["mario", "contra", "tetris"]}, "scores": {"attrs": {"processed": "unprocessed"}, "orig": {"pk": 45, "dp": 10}}}
    

提交回复
热议问题