Last updated: Apr 8, 2024
Reading timeยท3 min
The Python "TypeError: Object of type Decimal is not JSON serializable" occurs when we try to convert a Decimal to a JSON string.
To solve the error, extend the JSONEncoder
class and convert the decimal to
a string to preserve its precision.
Here is an example of how the error occurs.
import json from decimal import Decimal num = Decimal('3.14') # โ๏ธ TypeError: Object of type Decimal is not JSON serializable json_str = json.dumps({'salary': num})
We tried passing a Decimal to the json.dumps()
method but the method doesn't
handle Decimal values by default.
default
keyword argument to solve the errorOne way to solve the error is to use the default
keyword argument in the call
to the json.dumps
method.
import json from decimal import Decimal num = Decimal('3.14') json_str = json.dumps({'salary': num}, default=str) print(json_str) # ๐๏ธ {"salary": "3.14"} print(type(json_str)) # ๐๏ธ <class 'str'>
The json.dumps() method converts a Python object to a JSON formatted string.
default
keyword argument can be set to a function that gets called for objects that can't otherwise be serialized.We simply convert the Decimal
object to a string by passing it to the str
class.
DecimalEncoder
to solve the errorAn alternative way to solve the error is to extend from the JSONEncoder
class
and convert Decimal values to a string when serializing them.
import json from decimal import * num = Decimal('3.14') class DecimalEncoder(json.JSONEncoder): def default(self, obj): # ๐๏ธ if passed in object is instance of Decimal # convert it to a string if isinstance(obj, Decimal): return str(obj) # ๐๏ธ otherwise use the default behavior return json.JSONEncoder.default(self, obj) json_str = json.dumps({'salary': num}, cls=DecimalEncoder) print(json_str) # ๐๏ธ '{"salary": "3.14"}' print(type(json_str)) # ๐๏ธ <class 'str'>
The json.dumps() method converts a Python object to a JSON formatted string.
We extended from the JSONEncoder class.
The JSONEncoder
class supports the following objects and types by default.
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float, int and float derived Enums | number |
True | true |
False | false |
None | null |
Notice that the JSONEncoder
class doesn't support Decimal to JSON conversion
by default.
We can handle this by extending from the class and implementing a default()
method that returns a serializable object.
import json from decimal import * class DecimalEncoder(json.JSONEncoder): def default(self, obj): # ๐๏ธ If the passed in object is an instance of Decimal # convert it to a string if isinstance(obj, Decimal): return str(obj) # ๐๏ธ otherwise use the default behavior return json.JSONEncoder.default(self, obj)
if
statement, we check if the passed-in object is an instance of the Decimal
class and if it is, we convert it to a string and return the result.In all other cases, we let the base class's default method do the serialization.
To use a custom JSONEncoder
, specify it with the cls
keyword argument in
your call to the json.dumps()
method.
# โ set cls kwarg json_str = json.dumps({'salary': num}, cls=DecimalEncoder)
If you don't provide the cls
kwarg, the default JSONEncoder
is used.
simplejson
module to solve the errorAn alternative way to solve the error is to use the simplejson module.
You can install the module by running the following command from your terminal.
pip install simplejson # ๐๏ธ or pip3 pip3 install simplejson
The simplejson
module has native support for Decimal
values.
from decimal import Decimal import simplejson as json num = Decimal('3.14') json_str = json.dumps({'salary': num}) print(json_str) # ๐๏ธ {"salary": 3.14} print(type(json_str)) # ๐๏ธ <class 'str'>
Notice that we imported simplejson
and aliased it to json
.
The dumps
method from the simplejson
module has native support for Decimal
values, so we don't have to handle the conversion in any way.
The dumps
function optionally takes a use_decimal
keyword argument.
from decimal import Decimal import simplejson as json num = Decimal('3.14') json_str = json.dumps({'salary': num}, use_decimal=True) print(json_str) # ๐๏ธ {"salary": 3.14} print(type(json_str)) # ๐๏ธ <class 'str'>
If the use_decimal
keyword argument is set to True
, then decimal.Decimal
is natively serialized to JSON with full precision.
The default value of use_decimal
is True
.
You can learn more about the related topics by checking out the following tutorials: