我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
当前回答
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)
其他回答
如果你想传递一个包含小数的字典到请求库(使用json关键字参数),你只需要安装simplejson:
$ pip3 install simplejson
$ python3
>>> import requests
>>> from decimal import Decimal
>>> # This won't error out:
>>> requests.post('https://www.google.com', json={'foo': Decimal('1.23')})
这个问题的原因是,请求只在simplejson存在时才使用它,如果它没有安装,则回落到内置json。
对于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)
如果有人还在寻找答案,那么很有可能您的数据中有一个“NaN”,您正在尝试对其进行编码。因为NaN被Python视为浮点数。
我只有美元!
我扩展了一堆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
让我的生活轻松多了…
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'
希望该特性将包含在标准库中。