So - 
I think that is clear by now that in your case you really are not loosing
any precision with these numbers.

However, as noted, there is no way to customize Python JSON encoder
to encode an arbitrary decimal number in JSON, even though the standard does
allow it, and Python supports then via decimal.Decimal.

Short of a long term solution, like a __json__ protocol, or at least special
support in Python json module for objects of type "numbers.Number", 
the only way to go, is, as you are asking, being able to insert "raw strings into json".

Given that this feature can be needed now, I fashioned a JsonEncoder class that is able to 
do that - by annotating decimal.Decimal instances on encoding, and making
raw string replacements before returning the final encoded value.

This recipe is ready to be used at https://gist.github.com/jsbueno/5f5d200fd77dd1233c3063ad6ecb2eee 
(Note that I don't consider this approach fit for the stdlib due to having to rely on regular expressions,
and having to create a copy of the whole encoded json-body - if there is demand,
I might package it though).


Please enjoy.

  js
 -><-

On Thu, 8 Aug 2019 at 07:27, Richard Musil <risa2000x@gmail.com> wrote:
I have found myself in an awkward situation with current (Python 3.7) JSON module. Basically it boils down to how it handles floats. I had been hit on this particular case:

In [31]: float(0.6441726684570313)
Out[31]: 0.6441726684570312

but I guess it really does not matter.

What matters is that I did not find a way how to fix it with the standard `json` module. I have the JSON file generated by another program (C++ code, which uses nlohmann/json library), which serializes one of the floats to the value above. Then when reading this JSON file in my Python code, I can get either decimal.Decimal object (when specifying `parse_float=decimal.Decimal`) or float. If I use the latter the least significant digit is lost in deserialization.

If I use Decimal, the value is preserved, but there seems to be no way to "serialize it back". Writing a custom serializer:

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return str(o) # <- This becomes quoted in the serialized output
        return super.default(o)

seems to only allow returning "string" value, but then serializes it as a string! I.e. with the double quotes. What seems to be missing is an ability to return a "raw textual representation" of the serialized object which will not get mangled further by the `json` module.

I noticed that `simplejson` provides an explicit option for its standard serializing function, called `use_decimal`, which basically solves my problem., but I would just like to use the standard module, I guess.

So the question is, if something like `use_decimal` has been considered for the standard module, and if yes, why it was not implemented, or the other option could be to support "raw output" in the serializer, e.g. something like:
class DecimalEncoder(json.JSONEncoder):
    def raw(self, o):
        if isinstance(o, decimal.Decimal):
            return str(o) # <- This is a raw representation of the object
        return super.raw(o)
Where the returning values will be directly passed to the output stream without adding any additional characters. Then I could write my own Decimal serializer with few lines of code above.

If anyone would want to know, why the last digit matters (or why I cannot double quote the floats), it is because the file has a secure hash attached and this basically breaks it.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/WT6Z6YJDEZXKQ6OQLGAPB3OZ4OHCTPDU/
Code of Conduct: http://python.org/psf/codeofconduct/