У меня есть a Decimal('3.9')
как часть объекта и желание закодировать это к строке JSON, которая должна быть похожей {'x': 3.9}
. Я не забочусь о точности на стороне клиента, таким образом, плавание прекрасно.
Существует ли хороший способ сериализировать это? JSONDecoder не признает, что Десятичные объекты, и преобразовывающий в плавание заранее уступают {'x': 3.8999999999999999}
который является неправильным, и будет большой тратой пропускной способности.
Как насчет подклассификации json.JSONEncoder
?
class DecimalEncoder(json.JSONEncoder):
def _iterencode(self, o, markers=None):
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)._iterencode(o, markers)
Тогда используйте его так:
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
это можно сделать, добавив
elif isinstance(o, decimal.Decimal):
yield str(o)
в \Lib\json\encoder.py:JSONEncoder._iterencode
, но я надеялся на лучшее решение
3.9
не может быть точно представлено в IEEE floats, оно всегда будет представлено как 3.89999999999999
, например, попробуйте print 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)
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):
Итак:
>>> json.dumps(Decimal('3.9'))
'3.9'
Надеюсь, эта функция будет включена в стандартную библиотеку.