2010-02-16 2 views
5

Когда я использую объект питон десятичного просто что-то вроде:Распаковки численного значения из Python Decimal

from decimal import * 
dec = Decimal('3.432') 
print dec 

он будет печатать 3.432, так же, как я хочу, но если я пытаюсь поставить то же самое значение разла в Объект json, который я получаю в json, является десятичным («3.432»). Как я могу получить числовое значение из десятичного числа?

ответ

3

Вы получаете Decimal('3.432') в вашем объекте JSON? Странно ... как?

>>> from decimal import * 
>>> import json 
>>> json.dumps(Decimal('3.432')) 
.... 
TypeError: Decimal('3.432') is not JSON serializable 

В любом случае, если вы используете -десятичную вместо поплавка, вы, вероятно, не хотите терять точность путем преобразования его в поплавок. Если это так, то вы должны управлять процессом самостоятельно, первым гарантируя, что вы сохранить все данные, и дело с тем, что JSON не понимает десятичного типа:

>>> j = json.dumps(str(Decimal('3.000'))) 
>>> j 
'"3.000"' 
>>> Decimal(json.loads(j)) 
Decimal('3.000') 

Конечно, если вы не» t действительно заботится о точности (например, если какая-то библиотечная процедура дает вам Decimal), сначала конвертируйте в float, так как JSON справится с этим. Вы все еще не получит -десятичная позже, если вручную конвертировать снова с поплавком, хотя ...

Edit: Девин Jeanpierre указывает на существующую поддержку в json модуль для декодирования поплавка строки как нечто иное, чем поплавком с parse_float argument для load(), loads() и пользовательских JSONDecoders. Хотя это потребует от вас сначала конвертировать Decimals в float при кодировании (потеря точности), это может решить вторую половину проблемы немного более чисто, чем мой более ручной подход выше (обратите внимание, что это применимо ко всем поплавкам в ваших данных JSON). Вы также должны создать JSONEncoder subclass, чтобы выписать цифры для Десятичного числа без предварительной конвертации в float, что позволит избежать потери точности.

+0

Модуль json также может принимать пользовательский конструктор float, который будет принимать входные данные типа «3.1» и преобразовывать, скажем, в Десятичный, а не плавать, но это не будет точно переноситься на другие читатели json. (Это даже объясняется в документации, http://docs.python.org/library/json.html) –

+0

Пакет ijson, по-видимому, анализирует десятичные знаки в объектах Decimal(), даже если значение указано как регулярное десятичное число в файл. – Mittenchops

+0

@ Mittenchops Я не вижу этого поведения на 2.7. json.loads ('3.14159') возвращает значение с плавающей запятой 3.14159. Где вы видите, что вы описываете? –

4
>>> str(decimal.Decimal('3.1')) 
'3.1' 

Из-под коробки JSON использует несколько примитивных типов, таких как строки, сильно.

Ваш лучший выбор - конвертировать ваши Decimals в строки при создании вашего документа JSON с какого-либо объекта Python.

Преобразование строк обратно в десятичное число при преобразовании документа JSON обратно в объект Python.

1

Интересно, что я получаю исключение TypeError (это с запасом Python 2.6 json модуль - что вы используете?).

Очевидной альтернатива имеет очевидные недостатки:

>>> json.dumps(float(x)) 
'3.4319999999999999' 
>>> json.dumps(str(x)) 
'"3.432"' 

... один может дать вам довольно грязное приближение, а другой один седлает вас с цитатами. Если какая-либо из этих проблем приемлема в вашем приложении, продолжайте, но ни один из совпадений не соответствует конкретной спецификации.

Простейший (но не чистый!) Способ сделать то, что вы хотите с штоком json является monkeypatch вещи:

>>> json.encoder.FLOAT_REPR=str 
>>> json.dumps(float(x)) 
'3.432' 

Надлежащий/чистый способ это сделать (и использовать ;-) подкласс json.Encoder, который использует str вместо repr на поплавках - но это нетривиальная работа, увы.

0

Просто преобразуйте десятичную строку в float. Нет необходимости использовать Decimal.

>>> dec = float('3.432') 
>>> dec 
3.432 

Поплавковый объект - сериализуемый JSON. Вам не нужно заниматься какой-либо работой.