Вопрос-Ответ

Python JSON serialize a Decimal object

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

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

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

Переведено автоматически
Ответ 1

Simplejson 2.1 и выше имеет встроенную поддержку десятичного типа:

>>> 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'

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

Ответ 2

Я хотел бы, чтобы все знали, что я попробовал ответ Михаила Марчика на своем веб-сервере, на котором работал Python 2.6.5, и он работал нормально. Однако я обновился до Python 2.7, и он перестал работать. Я пытался придумать какой-то способ кодирования десятичных объектов, и вот что я придумал:

import decimal

class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super().default(o)

Обратите внимание, что это преобразует десятичное число в его строковое представление (например; "1.2300"), чтобы a. не потерять значащие цифры и b. предотвратить ошибки округления.

Надеюсь, это должно помочь всем, у кого возникли проблемы с Python 2.7. Я протестировал это, и, похоже, оно работает нормально. Если кто-нибудь заметит какие-либо ошибки в моем решении или предложит лучший способ, пожалуйста, дайте мне знать.

Пример использования:

json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
Ответ 3

Как насчет создания подклассов 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)
Ответ 4

Собственная опция Django отсутствует, поэтому я добавлю ее для следующего парня / нахала, который будет ее искать.

Начиная с Django 1.7.x, есть встроенная программа, DjangoJSONEncoder из которой вы можете это получить django.core.serializers.json.

import json
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict

model_instance = YourModel.object.first()
model_dict = model_to_dict(model_instance)

json.dumps(model_dict, cls=DjangoJSONEncoder)

Presto!

python json