Asked  7 Months ago    Answers:  5   Viewed   90 times

I have a Decimal('3.9') as part of an object, and wish to encode this to a JSON string which should look like {'x': 3.9}. I don't care about precision on the client side, so a float is fine.

Is there a good way to serialize this? JSONDecoder doesn't accept Decimal objects, and converting to a float beforehand yields {'x': 3.8999999999999999} which is wrong, and will be a big waste of bandwidth.

 Answers

12

How about subclassing json.JSONEncoder?

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            # wanted a simple yield str(o) in the next line,
            # but that would mean a yield on the line with super(...),
            # which wouldn't work (see my comment below), so...
            return (str(o) for o in [o])
        return super(DecimalEncoder, self).default(o)

Then use it like so:

json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
Tuesday, June 1, 2021
 
JustSteveKing
answered 7 Months ago
78

You can't serialize that as json, json has a much less flexible idea about what counts as a dict key than python.

You could transform the mapping into a sequence of key, value pairs, something like this:

>>> import json
>>> def remap_keys(mapping):
...     return [{'key':k, 'value': v} for k, v in mapping.iteritems()]
... 
>>> json.dumps(remap_keys({(1, 2): 'foo'}))
'[{"value": "foo", "key": [1, 2]}]'
Sunday, July 18, 2021
 
Alix
answered 5 Months ago
100

JSON (JavaScript Object Notation) is not designed for serializing DOM Nodes, you'll need to pull out the stuff you want by yourself and write it to an object, and then re-create the DOM Nodes from that if you need.

In fact, Chrome doesn't even execute your code:

TypeError: Converting circular structure to JSON
Thursday, August 5, 2021
 
mechalynx
answered 4 Months ago
79

The getcontext().prec set the precision of digits which Decimal lib will use to return any calculated number, that is, prec = 2 will return 2 digits (first=2, second=2) and in prec = 3 that will show three numbers(first=2, second=1, third=5).

However , there is a trick here. When you created the a and b variables, the Decimal used as precision the amount of digits from the number you gave to it. You can see that just calling the a or the b in your IDLE.

Saturday, August 21, 2021
 
jezrael
answered 4 Months ago
47

1.2246467991473532e-16 is close to 0 -- there are 16 zeroes between the decimal point and the first significant digit -- much as 3.1415926535897931 (the value of math.pi) is close to pi. The answer is correct to sixteen decimal places!

So if you want sin(pi) to equal 0, simply round it to a reasonable number of decimal places. 15 looks good to me and should be plenty for any application:

print round(math.sin(math.pi), 15)
Sunday, October 17, 2021
 
ram_p
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share