Extracting numerical value from Python Decimal

12,361

Solution 1

You get a Decimal('3.432') in your JSON object? Weird... how?

>>> from decimal import *
>>> import json
>>> json.dumps(Decimal('3.432'))
....
TypeError: Decimal('3.432') is not JSON serializable

In any case, if you are using a Decimal instead of a float, you probably don't want to lose precision by converting it to a float. If that's true, then you have to manage the process yourself by first ensuring you preserve all the data, and dealing with the fact that JSON doesn't understand the Decimal type:

>>> j = json.dumps(str(Decimal('3.000')))
>>> j
'"3.000"'
>>> Decimal(json.loads(j))
Decimal('3.000')

Of course, if you don't really care about the precision (e.g. if some library routine gives you a Decimal) just convert to a float first, as JSON can handle that. You still won't get a Decimal back later unless you manually convert again from float though...

Edit: Devin Jeanpierre points out the existing support in the json module for decoding float strings as something other than float with the parse_float argument for load(), loads() and custom JSONDecoders. While that would require you first to convert your Decimals to floats when encoding (losing precision) it could solve the second half of the problem a little more cleanly than my more manual approach above (note that it would apply to all floats in your JSON data). You should also be able to create a JSONEncoder subclass to write out the digits for the Decimal without first converting to float, which would let you avoid the loss of precision.

Solution 2

>>> str(decimal.Decimal('3.1'))
'3.1'

Out-of-the-box JSON uses a few primitive types, like strings, heavily.

Your best bet is to convert your Decimals to strings when creating your JSON document from some Python object.

Convert the strings back to Decimal when converting the JSON document back to a Python object.

Solution 3

Interesting -- what I get is a TypeError exception (that's with Python 2.6's stock json module -- what are you using?).

The obvious alternative have obvious imperfections:

>>> json.dumps(float(x))
'3.4319999999999999'
>>> json.dumps(str(x))
'"3.432"'

...one can give you a pretty dirty approximation, the other one saddles you with quotes. If either of these issues is acceptable in your application, go ahead, but neither matches you exact spec as posed.

The simplest (but not cleanest!!!) way to do what you want with stock json is to monkeypatch things:

>>> json.encoder.FLOAT_REPR=str
>>> json.dumps(float(x))
'3.432'

The proper/clean way is to make (and use;-) a subclass of json.Encoder which uses str instead of repr on floats -- but that's a non-trivial amount of work, alas.

Solution 4

You can convert decimal object to string and then the string to decimal

`>>>a = decimal.Decimal(3.0)

>>>str(a)

'3'

>>> int(str(a))

3 `

Share:
12,361
whatWhat
Author by

whatWhat

Updated on July 18, 2022

Comments

  • whatWhat
    whatWhat almost 2 years

    When I use the python Decimal object simply with something like:

    from decimal import *
    dec = Decimal('3.432')
    print dec
    

    it will print 3.432, just like I want, but if i try to put that same value dec into a json object what I get in the json is Decimal("3.432"). How can I just get the numerical value from decimal?

  • Devin Jeanpierre
    Devin Jeanpierre over 14 years
    the json module can also accept a custom float constructor, which will take an input like "3.1" and convert to, say, Decimal, not float, but this wouldn't exactly be portable to other json readers. (It's even explained in the documentation, docs.python.org/library/json.html )
  • Mittenchops
    Mittenchops over 10 years
    The package ijson seems to parse decimals into Decimal() objects, even when the value is listed as a regular decimal in the file.
  • Peter Hansen
    Peter Hansen over 10 years
    @Mittenchops I don't see that behaviour on 2.7. json.loads('3.14159') returns a float value of 3.14159. Where do you see what you describe?
  • Mittenchops
    Mittenchops over 10 years
    the behavior comes from the ijson module.
  • dwanderson
    dwanderson almost 8 years
    "but then why use Decimal?" - because someone else is returning Decimal but I don't need the precision. My current example is sqlalchemy - queries may return Decimal objects, but I want to check (unittest) against some pre-computed float, just as a sanity check. And those floats can easily live in a JSON. Just as a use case.