json.dumps 使用科学计数法输出小的浮点或十进制值,这对于发送此输出的 json-rpc 应用程序是不可接受的。
>>> import json
>>> json.dumps({"x": 0.0000001})
'{"x": 1e-07}'
我想要这个输出:
'{"x": 0.0000001}'
最好避免引入额外的依赖项。
json.dumps 使用科学计数法输出小的浮点或十进制值,这对于发送此输出的 json-rpc 应用程序是不可接受的。
>>> import json
>>> json.dumps({"x": 0.0000001})
'{"x": 1e-07}'
我想要这个输出:
'{"x": 0.0000001}'
最好避免引入额外的依赖项。
一种格式化方法
evil = {"x": 0.00000000001}
是窃取Decimal
's "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
。
这就是我会做的,即使这是一个蹩脚的方法。
我找不到答案来避免转换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
这是补充评论,不是避免使用科学记数法的完整答案json.dumps
。通过额外一轮解析,parse_float
选项 onjson.loads
可以帮助解决一些问题,例如
$ 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}'
在互联网上的某个地方找到
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]}'