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'}]