简体   繁体   English

Python 3.5 JSON 序列化一个十进制 object

[英]Python 3.5 JSON serialize a Decimal object

I need to encode into json a decimal value: 999999.99990000005 while not losing precision and not changing representation to string.我需要将十进制值编码到 json 中: 999999.99990000005 ,同时不丢失精度并且不将表示更改为字符串。 Expecting { "prc": 999999.99990000005 }期待{ "prc": 999999.99990000005 }

From [this post][1] i have this code.从 [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')}

but it produces a string但它会产生一个字符串

json.dumps(y, cls=DecimalEncoder)

'{"cPrc": "999999.99990000005"}'

replacing str(o) with float(o) in isinstance truncates the number.isinstance中用float(o)替换str(o)会截断数字。 Any way to get the non-string result?有什么方法可以获得非字符串结果? PS I cannot use any external modules like simplejson. PS 我不能使用任何像 simplejson 这样的外部模块。

EDIT: If I keep the value as a string, following produces a string too.编辑:如果我将值保留为字符串,则以下也会产生一个字符串。

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

It is not the most pretty but if you insist on using json we can create a custom decoder and have our encoder specify the type when handling decimal data. 它不是最漂亮的但是如果你坚持使用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)

The code above adds the decimal type as a flag for our decoder as well as encoding the decimal as a string to keep precision. 上面的代码将十进制类型添加为解码器的标志,并将十进制编码为字符串以保持精度。

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

The decoder checks for our decimal type flag and if so uses the decimal constructor. 解码器检查我们的十进制类型标志,如果是,则使用十进制构造函数。 For all other instances it uses default decoding 对于所有其他实例,它使用默认解码

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

The final result should take our input, encode it, and decode the result as a decimal object. 最终结果应该接受我们的输入,对其进行编码,并将结果解码为十进制对象。

Answering my own question. 回答我自己的问题。 I output Decimal objects surrounded by special character `. 我输出由特殊字符`包围的十进制对象。 Then remove it and the double-quote from text. 然后从文本中删除它和双引号。

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

From version 3.1 json library supports parse_float option that allows enconding/deconding as Decimal.从 3.1 版开始, json库支持parse_float选项,该选项允许将编码/解码为十进制。

Refer to official documentation for usage examples.使用示例请参考官方文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM