用科学记数法编写 JSON 浮点

write json float in scientific notation

提问人:Nico Schlömer 提问时间:6/5/2018 最后编辑:Jean-François FabreNico Schlömer 更新时间:6/2/2022 访问量:1636

问:

我想使用 Python 3.6+ 以科学记数法表示 JSON 文件中的浮点数。都不是

import json

a = 0.001234567

print(json.dumps(a))

json.encoder.FLOAT_REPR = lambda x: "{:e}".format(x)
print(json.dumps(a))

json.encoder.c_make_encoder = None
json.encoder.FLOAT_REPR = lambda x: "{:e}".format(x)
print(json.dumps(a))

工作:三者皆给print

0.001234567

而不是想要的

1.234567e-03

(请注意,最后一个版本至少在 Python 2.7.15rc1 中有效。

答案也应该适用于 s 列表。float

有什么提示吗?

python json python-3.6

评论

0赞 Nico Schlömer 6/5/2018
该问题现在标记为“stackoverflow.com/questions/32521823/ 已经有答案......”,但该答案不起作用
3赞 Jean-François Fabre 6/5/2018
看来我们必须为 Python 3.6 找到答案。不过,没有必要提出另一个问题。
1赞 Jean-François Fabre 6/6/2018
原始问题的答案:stackoverflow.com/a/1733105/6451573 没有猴子修补,值得一试

答:

3赞 PaulMcG 6/5/2018 #1

您必须为字典、列表、集合等添加一些特殊的大小写,但通过引用 中的抽象基类,可以避免显式测试特定类型。collections.abc

请注意,测试必须避免类型匹配,因为迭代 a 会给出一堆 1 字符的 s,它们也是可迭代的 s,依此类推,直到达到递归限制。我找不到表示“序列容器,但不是 str”的 ABC。SequencestrstrstrSequence

(我还必须回应 Alex Martelli 在相关文章中的批评,即必须做这么多工作来格式化特定类型,这说明了本模块中类设计中的问题。

import json
from collections.abc import Mapping, Sequence

a = 0.001234567

class ScientificNotationEncoder(json.JSONEncoder):
    def iterencode(self, o, _one_shot=False):
        if isinstance(o, float):
            return "{:e}".format(o)
        elif isinstance(o, Mapping):
            return "{{{}}}".format(', '.join('"{}" : {}'.format(str(ok), self.iterencode(ov))
                                             for ok, ov in o.items()))
        elif isinstance(o, Sequence) and not isinstance(o, str):
            return "[{}]".format(', '.join(map(self.iterencode, o)))
        return ', '.join(super().iterencode(o, _one_shot))

aout = json.dumps([a, a, "xyzzy", 42, {'z': a}, (a, a, a),],
                  cls=ScientificNotationEncoder)
print(aout)

# loading back in seems to still work okay!
print(json.loads(aout))

指纹:

[1.234567e-03, 1.234567e-03, "xyzzy", 42, {"z" : 1.234567e-03}, [1.234567e-03, 1.234567e-03, 1.234567e-03]]
[0.001234567, 0.001234567, 'xyzzy', 42, {'z': 0.001234567}, [0.001234567, 0.001234567, 0.001234567]]

评论

0赞 Nico Schlömer 6/5/2018
谢谢你的回答。这仅在转换单个浮点数时有效。放进去就行不通了。[a, a]
0赞 Nico Schlömer 6/5/2018
现在不为口述工作。如果必须将所有案件单独列出,这可能是一场艰苦的战斗。{"key": 0.00123}
0赞 PaulMcG 6/5/2018
如果您可以使用抽象类型,也许不会那么可怕collections.abc
0赞 cs95 6/6/2018
元宇宙上关于您重新开放的讨论:meta.stackoverflow.com/q/369085/4909087
1赞 Jean-François Fabre 6/6/2018
这个答案的这个代码看起来比 stackoverflow.com/a/1733105/6451573 略好,这应该是这个问题的原始问题。我认为如果它张贴在那里,并有更多的解释会更有意义。
0赞 Nico Schlömer 6/2/2022 #2

最终,我创建了自己的 json 库,可以格式化浮点数 fjson。安装方式

pip install fjson

并用作

import math
import fjson


data = {"a": 1, "b": math.pi}
string = fjson.dumps(data, float_format=".6e", indent=2, separators=(", ", ": "))
print(string)
{
  "a": 1,
  "b": 3.141593e+00
}