【问题标题】:Python 3.5 JSON serialize a Decimal objectPython 3.5 JSON 序列化 Decimal 对象
【发布时间】:2018-11-15 08:42:07
【问题描述】:

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

来自 [this post][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"}'

isinstance 中用float(o) 替换str(o) 会截断数字。 有什么方法可以获得非字符串结果? 附言我不能使用任何像 simplejson 这样的外部模块。

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

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

【问题讨论】:

  • 您确定要这样做吗?在读取 JSON 时,您几乎肯定会失去这种精度,因为大多数库会将其作为浮点数引入。
  • 字符串结果有什么问题?为什么你不能使用它?
  • 请参阅问题中的编辑,了解为什么我不能保留字符串。
  • @Steve 你说你不能使用像 simplejson 这样的外部模块,所以我假设你知道 simplejson 会免费编码/解码十进制值,对吧?
  • 它序列化为一个字符串,因为您所需的精度水平高于 JSON 支持的基本数据类型所能处理的任何水平。您可能想要做的是将其序列化为当前正在执行的字符串,然后调整 反序列化 过程以将其作为小数处理

标签: python json


【解决方案1】:

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

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("`\"",'')

【讨论】:

    【解决方案2】:

    这不是最漂亮的,但如果您坚持使用 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)
    

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

    【讨论】:

      猜你喜欢
      • 2010-12-29
      • 2018-04-29
      • 2010-11-30
      • 2017-09-26
      • 1970-01-01
      • 2017-09-03
      相关资源
      最近更新 更多