【问题标题】:Python 3.x cannot serialize Decimal() to JSONPython 3.x 无法将 Decimal() 序列化为 JSON
【发布时间】:2017-09-26 11:57:12
【问题描述】:

我之前问过这个问题,它被标记为与this 重复,但是接受的答案不起作用,甚至 pylint 显示代码中有错误。

我想做什么:

from decimal import Decimal
import json

thang = {
    'Items': [{'contact_id': Decimal('2'), 'street_name': 'Asdasd'}, {'contact_id': Decimal('1'), 'name': 'Lukas', 'customer_id': Decimal('1')}],
     'Count': 2}

print(json.dumps(thang))

这会引发: TypeError: Object of type 'Decimal' is not JSON serializable

所以我尝试了链接的answer

from decimal import Decimal
import json

thang = {
    'Items': [{'contact_id': Decimal('2'), 'street_name': 'Asdasd'}, {'contact_id': Decimal('1'), 'name': 'Lukas', 'customer_id': Decimal('1')}],
     'Count': 2}


class DecimalEncoder(json.JSONEncoder):
    def _iterencode(self, o, markers=None):
        if isinstance(o, 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)._iterencode(o, markers)


print(json.dumps(thang, cls=DecimalEncoder))

这里 linter 显示 return super(DecimalEncoder, self)._iterencode(o, markers) 行有错误,因为 Super of 'DecimalEncoder' has no '_iterencode' member 和运行时抛出 TypeError: Object of type 'Decimal' is not JSON serializable

我该如何进行这项工作?

【问题讨论】:

    标签: python json python-3.x serialization


    【解决方案1】:

    我想序列化 Decimal 为 JSON,并将其反序列化返回到其他地方字典中的实际 Decimal 类对象。

    这是适用于我的示例程序(Python 3.6):

    import json
    from decimal import Decimal
    import decimal
    
    class DecimalEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, decimal.Decimal):
                return {'__Decimal__': str(obj)}
            # Let the base class default method raise the TypeError
            return json.JSONEncoder.default(self, obj)
    
    def as_Decimal(dct):
        if '__Decimal__' in dct:
            return decimal.Decimal(dct['__Decimal__'])
        return dct
    
    
    sample_dict = {
            "sample1": Decimal("100"), 
            "sample2": [ Decimal("2.0"), Decimal("2.1") ],
            "sample3": Decimal("3.1415"),
            "other": "hello!"
        }
    print("1. sample_dict is:\n{0}\n".format(sample_dict))
    
    sample_dict_encoded_as_json_string = json.dumps(sample_dict, cls=DecimalEncoder)
    print("2. sample_dict_encoded_as_json_string is:\n{0}\n".format(sample_dict_encoded_as_json_string))
    
    sample_dict_recreated = json.loads(sample_dict_encoded_as_json_string, object_hook=as_Decimal)
    print("3. sample_dict_recreated is:\n{0}\n".format(sample_dict_recreated))
    

    这是输出:

    1. sample_dict is:
    {'sample1': Decimal('100'), 'sample2': [Decimal('2.0'), Decimal('2.1')], 'sample3': Decimal('3.1415'), 'other': 'hello!'}
    
    2. sample_dict_encoded_as_json_string is:
    {"sample1": {"__Decimal__": "100"}, "sample2": [{"__Decimal__": "2.0"}, {"__Decimal__": "2.1"}], "sample3": {"__Decimal__": "3.1415"}, "other": "hello!"}
    
    3. sample_dict_recreated is:
    {'sample1': Decimal('100'), 'sample2': [Decimal('2.0'), Decimal('2.1')], 'sample3': Decimal('3.1415'), 'other': 'hello!'}
    

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      结果证明该答案已过时,并且有另一个 answer 具有有效的解决方案:

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

      请注意,这会将十进制转换为其字符串表示形式(例如,"1.2300")为 a。不丢失有效数字和 b。防止舍入错误。

      【讨论】:

      • 这完全违背了decimal.Decimal 类的目的。它应该序列化为字符串而不是浮点数,因为浮点数不准确。
      • 完全同意。将 Decimal 序列化为浮点数的答案不应该是最佳答案,因为它非常不准确。例如,您最终可能会因为浮点舍入错误而违反法律合同。
      猜你喜欢
      • 2018-11-15
      • 2020-03-15
      • 2010-12-29
      • 2017-05-26
      • 1970-01-01
      • 2016-12-01
      相关资源
      最近更新 更多