Convert python dictionaries with Decimal keys to JSON using custom encoder Convert python dictionaries with Decimal keys to JSON using custom encoder json json

Convert python dictionaries with Decimal keys to JSON using custom encoder


No, you can't hook the handling of keys, you'll have to convert them before you encode. You can do so with a recursive handler like:

from functools import singledispatch@singledispatchdef string_keys(obj):    return obj@string_keys.register(dict)def _(d):    return {str(k): string_keys(v) for k, v in d.items()}@string_keys.register(list)def _(l):    return [string_keys(v) for v in l]

All this does is convert a nested structure of lists and dicts recursively where all keys are forced to be strings.

Use this when converting to JSON:

json_encoded = json.dumps(string_keys(data))

You can extend this to handle Decimal objects (outside of keys) too by adding another registry:

@string_keys.register(Decimal)def _(d):    return str(d)

Going the other way is a little tricky, unless you explicitly mark up Decimal keys (with a prefix, say), you can't easily distinguish between keys that were strings to start with and Decimal values. You could use a try/except approach here:

from functools import singledispatch@singledispatchdef keys_to_decimal(obj):    return obj@keys_to_decimal.register(dict)def _(d):    def try_decimal(k):        try:            return Decimal(k)        except ValueError:            return k    return {try_decimal(k): keys_to_decimal(v) for k, v in d.items()}@keys_to_decimal.register(list)def _(l):    return [keys_to_decimal(v) for v in l]

Demo:

>>> string_keys([{Decimal(0): 'foo'}])[{'0': 'foo'}]>>> keys_to_decimal(string_keys([{Decimal(0): 'foo'}]))[{Decimal('0'): 'foo'}]