Python 3.5 JSON序列化一个Decimal对象

时间:2018-06-05 19:03:02

标签: python json

我需要将json编码为十进制值:999999.99990000005,同时不会丢失精度而不会将表示更改为字符串。期待{ "prc" : 999999.99990000005 }

从[这篇文章] [1]我有这段代码。

import json
import decimal

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

y = { 'prc' : decimal.Decimal('999999.99990000005')}

但它会产生一个字符串

json.dumps(y, cls=DecimalEncoder)

'{"cPrc": "999999.99990000005"}'

str(o)替换为float(o)中的isinstance会截断该号码。 任何获得非字符串结果的方法? 附:我不能使用像simplejson这样的任何外部模块。

编辑: 如果我将值保留为字符串,则以下也会生成字符串。

>>> x = json.loads("""{ "cPrc" : "999999.99990000005" }""", parse_float=decimal.Decimal)
>>> x
{'cPrc': '999999.99990000005'}

2 个答案:

答案 0 :(得分:1)

这不是最漂亮但是如果你坚持使用json我们可以创建一个自定义解码器并让我们的编码器在处理十进制数据时指定类型。

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, decimal.Decimal):
            return {
                "_type": "decimal",
                "value": str(obj)
            }
        return super(DecimalEncoder, self).default(obj)

上面的代码将十进制类型添加为我们解码器的标志,并将十进制编码为字符串以保持精度。

class DecimalDecoder(json.JSONDecoder):
    def __init__(self, *args, **kwargs):
        json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)

    def object_hook(self, obj):
        if '_type' not in obj:
            return obj
        type = obj['_type']
        if type == 'decimal':
            return decimal.Decimal(obj['value'])
        return obj

解码器检查我们的十进制类型标志,如果是,则使用十进制构造函数。对于所有其他实例,它使用默认解码

input = { 'prc' : decimal.Decimal('999999.99990000005')}
encoded = json.dumps(input, cls=DecimalEncoder)
decoded = json.loads(encoded, cls=DecimalDecoder)

最终结果应该接受我们的输入,对其进行编码,并将结果解码为十进制对象。

答案 1 :(得分:0)

回答我自己的问题。 我输出由特殊字符`包围的十进制对象。然后从文本中删除它和双引号。

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return '`'+str(o)+'`' #` is special, will be removed later
        return super(DecimalEncoder, self).default(o)

json.dumps(y, cls=DecimalEncoder).replace("\"`",'').replace("`\"",'')