Python JSON 序列化 Decimal 对象
我有一个对象里面有个 Decimal('3.9')
,我想把它转成一个JSON字符串,格式应该是 {'x': 3.9}
。我不在乎客户端的精度,所以用浮点数就可以了。
有没有好的方法来处理这个?JSONDecoder不支持Decimal对象,提前转换成浮点数的话会变成 {'x': 3.8999999999999999}
,这就不对了,而且会浪费很多带宽。
24 个回答
270
我想告诉大家,我在运行Python 2.6.5的网络服务器上试过Michał Marczyk的答案,效果很好。不过,当我升级到Python 2.7后,它就不再工作了。我试着想办法对Decimal对象进行编码,最后想出了这个方法:
import decimal
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super().default(o)
请注意,这个方法会把小数转换成字符串形式(比如:"1.2300"
),这样可以避免丢失重要的数字,并且防止出现四舍五入的错误。
希望这能帮助到那些在使用Python 2.7时遇到问题的人。我测试过,效果不错。如果有人发现我这个方法的bug,或者有更好的解决办法,请告诉我。
使用示例:
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
277
Simplejson 2.1及更高版本原生支持Decimal类型:
>>> import simplejson as json
>>> json.dumps(Decimal('3.9'), use_decimal=True)
'3.9'
请注意,use_decimal
默认值为True
:
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=True,
namedtuple_as_object=True, tuple_as_array=True,
bigint_as_string=False, sort_keys=False, item_sort_key=None,
for_json=False, ignore_nan=False, **kw):
所以:
>>> json.dumps(Decimal('3.9'))
'3.9'
希望这个功能能被加入到标准库中。
182
那我们来看看怎么去扩展一下 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)
然后可以这样使用它:
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)