TypeError: Object of type Decimal is not JSON serializable

avatar
Borislav Hadzhiev

Last updated: Apr 8, 2024
3 min

banner

# TypeError: Object of type Decimal is not JSON serializable

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.

main.py
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})

type error object of type decimal is not json serializable

We tried passing a Decimal to the json.dumps() method but the method doesn't handle Decimal values by default.

# Use the default keyword argument to solve the error

One way to solve the error is to use the default keyword argument in the call to the json.dumps method.

main.py
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'>

use default keyword argument to solve error

The json.dumps() method converts a Python object to a JSON formatted string.

The 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.

# Create a custom DecimalEncoder to solve the error

An alternative way to solve the error is to extend from the JSONEncoder class and convert Decimal values to a string when serializing them.

main.py
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'>

create custom decimal encoder to solve error

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.

PythonJSON
dictobject
list, tuplearray
strstring
int, float, int and float derived Enumsnumber
Truetrue
Falsefalse
Nonenull

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.

main.py
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)
In our 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.

main.py
# โœ… set cls kwarg json_str = json.dumps({'salary': num}, cls=DecimalEncoder)

If you don't provide the cls kwarg, the default JSONEncoder is used.

# Using the simplejson module to solve the error

An 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.

shell
pip install simplejson # ๐Ÿ‘‡๏ธ or pip3 pip3 install simplejson

install simplejson module

The simplejson module has native support for Decimal values.

main.py
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.

main.py
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.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev