Search code examples
pythonjsontuples

Preserve Python tuples with JSON


I'm still a little new to this, so I might not know all the conventional terms for things:

Is it possible to preserve Python tuples when encoding with JSON? Right now json.loads(json.dumps(tuple)) gives me a list back. I don't want to convert my tuples to lists, but I want to use JSON. So, are there options?

The reason why: I'm creating an app that uses multi-dimensional arrays, not always the same shape. I've got some class methods that use recursion to probe the arrays and cast the endpoints as a string or int. I recently realized that (based on how my recursion works) I can use tuples to prevent deeper recursive searching of arrays (Python rawks). This could come in handy in situations where I know I for sure I won't need to be probing any deeper into my data structures.


Solution

  • You can write a highly-specialzed encoder and a decoder hook:

    import json
    
    class MultiDimensionalArrayEncoder(json.JSONEncoder):
        def encode(self, obj):
            def hint_tuples(item):
                if isinstance(item, tuple):
                    return {'__tuple__': True, 'items': item}
                if isinstance(item, list):
                    return [hint_tuples(e) for e in item]
                if isinstance(item, dict):
                    return {key: hint_tuples(value) for key, value in item.items()}
                else:
                    return item
    
            return super(MultiDimensionalArrayEncoder, self).encode(hint_tuples(obj))
    
    def hinted_tuple_hook(obj):
        if '__tuple__' in obj:
            return tuple(obj['items'])
        else:
            return obj
    
    
    enc = MultiDimensionalArrayEncoder()
    jsonstring =  enc.encode([1, 2, (3, 4), [5, 6, (7, 8)]])
    
    print jsonstring
    
    # [1, 2, {"items": [3, 4], "__tuple__": true}, [5, 6, {"items": [7, 8], "__tuple__": true}]]
    
    print json.loads(jsonstring, object_hook=hinted_tuple_hook)
    
    # [1, 2, (3, 4), [5, 6, (7, 8)]]