Formatting a number to scientific notation and saving it without surrounding quotes [duplicate]
I would like to represent floats in a JSON file in scientific notation using Python 3.6+. None of
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))
work: All three print
s give
0.001234567
instead of the desired
1.234567e-03
(Note that the last version works at least in in Python 2.7.15rc1.)
The answer should work with lists of float
s as well.
Any hints?
You have to add some special casing for dicts, lists, sets, etc., but by referencing abstract base classes from collections.abc
, you avoid explicitly testing for specific types.
Note that the test for Sequence
has to avoid matching on str
types, since iterating over a str
gives a bunch of 1-character str
s, which are also iterable Sequence
s, and so on until you reach the recursion limit. I could not find an ABC that represents "a sequence container, but not a str".
(I also have to echo Alex Martelli's criticism from a related post, that having to do this much work just to format a particular type speaks to issues in the design of the classes in this module.)
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))
Prints:
[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]]