Python JSON сериализирует Десятичный объект

У меня есть a Decimal('3.9') как часть объекта и желание закодировать это к строке JSON, которая должна быть похожей {'x': 3.9}. Я не забочусь о точности на стороне клиента, таким образом, плавание прекрасно.

Существует ли хороший способ сериализировать это? JSONDecoder не признает, что Десятичные объекты, и преобразовывающий в плавание заранее уступают {'x': 3.8999999999999999} который является неправильным, и будет большой тратой пропускной способности.

204
задан dreftymac 6 November 2018 в 18:47
поделиться

4 ответа

Как насчет подклассификации 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)
132
ответ дан 23 November 2019 в 04:54
поделиться

это можно сделать, добавив

    elif isinstance(o, decimal.Decimal):
        yield str(o)

в \Lib\json\encoder.py:JSONEncoder._iterencode, но я надеялся на лучшее решение

.
-6
ответ дан 23 November 2019 в 04:54
поделиться

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)
11
ответ дан 23 November 2019 в 04:54
поделиться

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'

Надеюсь, эта функция будет включена в стандартную библиотеку.

204
ответ дан 23 November 2019 в 04:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: