I asked this question earlier, and it was marked as duplicate of this, but the accepted answer does not work and even pylint shows that there are errors in the code.
What I want to do:
from decimal import Decimal
import json
thang = {
'Items': [{'contact_id': Decimal('2'), 'street_name': 'Asdasd'}, {'contact_id': Decimal('1'), 'name': 'Lukas', 'customer_id': Decimal('1')}],
'Count': 2}
print(json.dumps(thang))
This throws:
TypeError: Object of type 'Decimal' is not JSON serializable
So I tried the linked answer:
from decimal import Decimal
import json
thang = {
'Items': [{'contact_id': Decimal('2'), 'street_name': 'Asdasd'}, {'contact_id': Decimal('1'), 'name': 'Lukas', 'customer_id': Decimal('1')}],
'Count': 2}
class DecimalEncoder(json.JSONEncoder):
def _iterencode(self, o, markers=None):
if isinstance(o, 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)._iterencode(o, markers)
print(json.dumps(thang, cls=DecimalEncoder))
And here the linter shows that line return super(DecimalEncoder, self)._iterencode(o, markers)
has errors, because Super of 'DecimalEncoder' has no '_iterencode' member
and when ran throws
TypeError: Object of type 'Decimal' is not JSON serializable
How do I make this work?
To JSON serialize a Decimal object with Python, we can use the json. dumps method from the simplejson module with use_decimal set to True .
The Python "TypeError: Object of type method is not JSON serializable" occurs when we try to serialize a method to JSON. To solve the error, make sure to call the method and serialize the object that the method returns.
I wanted to serialize Decimal to JSON, and also deserialize it back to actual Decimal class objects in a dictionary elsewhere.
Here is my sample program which works for me (Python 3.6):
import json
from decimal import Decimal
import decimal
class DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, decimal.Decimal):
return {'__Decimal__': str(obj)}
# Let the base class default method raise the TypeError
return json.JSONEncoder.default(self, obj)
def as_Decimal(dct):
if '__Decimal__' in dct:
return decimal.Decimal(dct['__Decimal__'])
return dct
sample_dict = {
"sample1": Decimal("100"),
"sample2": [ Decimal("2.0"), Decimal("2.1") ],
"sample3": Decimal("3.1415"),
"other": "hello!"
}
print("1. sample_dict is:\n{0}\n".format(sample_dict))
sample_dict_encoded_as_json_string = json.dumps(sample_dict, cls=DecimalEncoder)
print("2. sample_dict_encoded_as_json_string is:\n{0}\n".format(sample_dict_encoded_as_json_string))
sample_dict_recreated = json.loads(sample_dict_encoded_as_json_string, object_hook=as_Decimal)
print("3. sample_dict_recreated is:\n{0}\n".format(sample_dict_recreated))
And here is the output:
1. sample_dict is:
{'sample1': Decimal('100'), 'sample2': [Decimal('2.0'), Decimal('2.1')], 'sample3': Decimal('3.1415'), 'other': 'hello!'}
2. sample_dict_encoded_as_json_string is:
{"sample1": {"__Decimal__": "100"}, "sample2": [{"__Decimal__": "2.0"}, {"__Decimal__": "2.1"}], "sample3": {"__Decimal__": "3.1415"}, "other": "hello!"}
3. sample_dict_recreated is:
{'sample1': Decimal('100'), 'sample2': [Decimal('2.0'), Decimal('2.1')], 'sample3': Decimal('3.1415'), 'other': 'hello!'}
Hope this helps!
That answer turned out to be outdated and there was another answer with the working solution:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
Note that this will convert the decimal to its string representation (e.g.; "1.2300"
) to a. not lose significant digits and b. prevent rounding errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With