【问题标题】:Disable scientific notation in python json.dumps output在 python json.dumps 输出中禁用科学计数法
【发布时间】:2013-09-27 00:13:53
【问题描述】:

json.dumps 使用科学计数法输出小的浮点或十进制值,这对于该输出发送到的 json-rpc 应用程序是不可接受的。

>>> import json
>>> json.dumps({"x": 0.0000001})
'{"x": 1e-07}'

我想要这个输出:

'{"x": 0.0000001}'

最好避免引入额外的依赖项。

【问题讨论】:

  • 如果它实际上不理解 JSON...,我会犹豫将其称为“JSON-RPC”应用程序
  • 或者浮动的那件事......
  • 您唯一的选择是将其转换为字符串。这行得通吗?

标签: python json scientific-notation


【解决方案1】:

一种格式化方式

evil = {"x": 0.00000000001}

是窃取Decimal 的“f”格式化程序。这是我发现的唯一一种避免裁剪问题和指数的简单方法,但它不节省空间

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

要使用它,您可以制作一个将输入“十进制化”的编码器

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

或者,当然,您可以将十进制化移到一个函数中并在 json.dumps 之前调用它。

这就是我会做的,即使这是一个蹩脚的方法。

【讨论】:

    【解决方案2】:

    在网上某处找到

    import json
    from json import encoder
    encoder.FLOAT_REPR = lambda o: format(o, '.2f')
    

    之后

    >>> json.dumps({'gps': [51.5, 17.5]})
    '{"gps": [51.5, 17.5]}'
    

    【讨论】:

    • 这似乎不起作用:json.dumps({'a': 1/2000000}) 给了我'{"a": 5e-07}',而问题是如何摆脱科学记数法。
    【解决方案3】:

    我找不到答案来避免将0.00001 转换为1e-5 的问题,所以我写了一个pretty_float_json_dumps 函数。它在我的项目中运行良好!希望它可以帮助某人!

    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
    

    【讨论】:

    • 泰。我编辑了一个命名错误,似乎运行正常。你知道这是如何执行的吗?
    【解决方案4】:

    这是补充评论,不是json.dumps 中避免科学记数法的完整答案。通过额外一轮解析,json.loads 上的 parse_float 选项可以帮助解决一些问题,例如

    $ python
    Python 3.7.10 | packaged by conda-forge | (default, Feb 19 2021, 16:07:37) 
    [GCC 9.3.0] on linux
    Type "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}'
    

    这只会避免舍入为零的小值的科学记数法。虽然这对于大型数据集效率不高,但它可以在某些用例中提供帮助。这并不能完全避免科学记数法。

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

    【讨论】:

      猜你喜欢
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-01
      相关资源
      最近更新 更多