Disable scientific notation in python json.dumps output Disable scientific notation in python json.dumps output json json

Disable scientific notation in python json.dumps output


One way to format

evil = {"x": 0.00000000001}

is to steal Decimal's "f" formatter. It's the only easy way I've found that avoids both cropping problems and exponents, but it's not space efficient.

class FancyFloat(float):    def __repr__(self):        return format(Decimal(self), "f")

To use it you can make an encoder that "decimalize"s the input

class JsonRpcEncoder(json.JSONEncoder):    def decimalize(self, val):        if isinstance(val, dict):            return {k:self.decimalize(v) for k,v in val.items()}        if isinstance(val, (list, tuple)):            return type(val)(self.decimalize(v) for v in val)        if isinstance(val, float):            return FancyFloat(val)        return val    def encode(self, val):        return super().encode(self.decimalize(val))JsonRpcEncoder().encode(evil)#>>> '{"x": 0.00000000000999999999999999939496969281939810930172340963650867706746794283390045166015625}'

or, of course, you could move the decimalization out into a function and call that before json.dumps.

That's how I would do it, even if it's a lame method.


I can't find an answer to avoid the problem that converts 0.00001 to 1e-5,so I wrote a pretty_float_json_dumps function. It works fine in my project! Hope it can help someone!!

def pretty_float_json_dumps(json_obj):    dumps_str = ""    if isinstance(json_obj, dict):         dumps_str += "{"        for k,v in json_obj.items():            dumps_str += json.dumps(k)+":"            if isinstance(v, float):                 float_tmp_str = ("%.16f" % v).rstrip("0")                dumps_str += (float_tmp_str+'0' if float_tmp_str.endswith('.') else float_tmp_str) + ','            elif isinstance(v, list) or isinstance(v, dict):                 dumps_str += pretty_float_json_dumps(v)+','            else:                dumps_str += pretty_float_json_dumps(v)+','        if dumps_str.endswith(','):            dumps_str = dumps_str[:-1]        dumps_str += "}"    elif isinstance(json_obj, list):         dumps_str += "["        for v in json_obj:            if isinstance(v, float):                 float_tmp_str = ("%.16f" % v).rstrip("0")                dumps_str += (float_tmp_str+'0' if float_tmp_str.endswith('.') else float_tmp_str) + ','            elif isinstance(v, list) or isinstance(v, dict):                 dumps_str += pretty_float_json_dumps(v)+','            else:                dumps_str += pretty_float_json_dumps(v)+','        if dumps_str.endswith(','):            dumps_str = dumps_str[:-1]        dumps_str += "]"    else:        dumps_str += json.dumps(json_obj)    return dumps_str


This is supplemental commentary, not a complete answer for avoiding scientific notation in json.dumps. With an extra round of parsing, the parse_float option on json.loads can help with some things, e.g.

$ pythonPython 3.7.10 | packaged by conda-forge | (default, Feb 19 2021, 16:07:37) [GCC 9.3.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import json>>> data = {"x": 0.0000001}>>> json.dumps(data)'{"x": 1e-07}'>>> data = json.loads(json.dumps(data), parse_float=lambda x: round(float(x), 6))>>> json.dumps(data)'{"x": 0.0}'

This only avoids scientific notation for small values that are rounded to zero. While that is not efficient for large datasets, it can help in some use-cases. This does not completely avoid scientific notation.

>>> data = {"x": 0.00001}>>> data = json.loads(json.dumps(data), parse_float=lambda x: round(float(x), 6))>>> json.dumps(data)'{"x": 1e-05}'