我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。

有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。


当前回答

在我的Flask应用程序中,它使用python 2.7.11, Flask alchemy(具有'db.decimal'类型)和Flask Marshmallow(用于'即时'序列化器和反序列化器),我有这个错误,每次我做GET或POST。序列化器和反序列化器未能将十进制类型转换为任何可识别的JSON格式。

然后,我做了一个“pip install simplejson” 只要加上

import simplejson as json

序列化器和反序列化器又开始工作了。我什么也没做…… 十进制显示为'234.00'浮点格式。

其他回答

对于Django用户:

最近遇到TypeError: Decimal('2337.00')不是JSON可序列化的 当JSON编码时,即JSON .dump (data)

解决方案:

# converts Decimal, Datetime, UUIDs to str for Encoding
from django.core.serializers.json import DjangoJSONEncoder  

json.dumps(response.data, cls=DjangoJSONEncoder)

但是,现在Decimal值将是一个字符串,现在我们可以在解码数据时显式设置Decimal /float值解析器,使用json.loads中的parse_float选项:

import decimal 

data = json.loads(data, parse_float=decimal.Decimal) # default is float(num_str)

Simplejson 2.1及更高版本原生支持十进制类型:

>>> 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):

So:

>>> json.dumps(Decimal('3.9'))
'3.9'

希望该特性将包含在标准库中。

3.9不能准确地在IEEE浮点数中表示,它总是以3.899999999999999999表示,例如,尝试打印repr(3.9),你可以在这里阅读更多信息:

http://en.wikipedia.org/wiki/Floating_point http://docs.sun.com/source/806-3568/ncg_goldberg.html

所以如果你不想要float,唯一的选项你必须将它作为字符串发送,并允许自动将十进制对象转换为JSON,做这样的事情:

import decimal
from django.utils import simplejson

def json_encode_decimal(obj):
    if isinstance(obj, decimal.Decimal):
        return str(obj)
    raise TypeError(repr(obj) + " is not JSON serializable")

d = decimal.Decimal('3.5')
print simplejson.dumps([d], default=json_encode_decimal)

我将分享flask 2.1.0对我有用的东西 当我创建字典时,必须从jsonify使用我使用四舍五入:

json_dict['price'] = round(self.price, ndigits=2) if self.price else 0

这样我就可以返回D.DD号或0,而不需要使用全局配置。这很好,因为有些十进制坐标需要更大,比如经纬度坐标。

return jsonify(json_dict)

我只有美元!

我扩展了一堆JSON编码器,因为我正在为我的web服务器序列化大量数据。这里有一些不错的代码。请注意,它可以很容易地扩展到几乎任何你想要的数据格式,并将3.9再现为“thing”:3.9

JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_newdefault(self, o):
    if isinstance(o, UUID): return str(o)
    if isinstance(o, datetime): return str(o)
    if isinstance(o, time.struct_time): return datetime.fromtimestamp(time.mktime(o))
    if isinstance(o, decimal.Decimal): return str(o)
    return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_newdefault

让我的生活轻松多了…