【问题标题】:Object of type 'Decimal' is not JSON serializable“十进制”类型的对象不是 JSON 可序列化的
【发布时间】:2020-08-06 07:25:35
【问题描述】:

由于客户函数错误,Lambda 执行失败,状态为 200:“十进制”类型的对象不是 JSON 可序列化的

我浏览了以下链接中的所有现有解决方案,但对我没有任何帮助。我究竟做错了什么?: Python JSON serialize a Decimal object

import json
import boto3
import decimal


client = boto3.resource('dynamodb')
table = client.Table('table')

def lambda_handler(event, context):
    method = event["httpMethod"]
    print(event)
    if method=="POST":
        return POST(event)
    elif method=="DELETE":
        return DELETE(event)
    elif method=="GET":
        return GET(event)

#the respons format
def send_respons(responseBody, statusCode):
    response = {
        "statusCode": statusCode,
        "headers": {
            "my_header": "my_value"
        },
        "body": json.dumps(responseBody),
        "isBase64Encoded": 'false'
    }
    return response
    

def GET(event):
    tab = table.scan()['Items']
    ids = []
            for item in tab:
                    ids.append({"id":item["id"], "decimalOBJ":decimal.Decimal(item["decimalOBJ"]}))
            return send_respons(ids, 201)

【问题讨论】:

    标签: python json


    【解决方案1】:

    这里是扩展JSONEncoder 以处理Decimal 类型的示例,该类型也在json docs 中指定

    from decimal import Decimal
    
    class DecimalEncoder(json.JSONEncoder):
      def default(self, obj):
        if isinstance(obj, Decimal):
          return str(obj)
        return json.JSONEncoder.default(self, obj)
    

    调用它使用

    json.dumps(some_object, cls=DecimalEncoder)
    

    通过转换为str 可以保持良好的精度,而无需依赖外部包。

    【讨论】:

      【解决方案2】:

      看来你有两个选择:

      1. 可能最简单,您可以序列化 Decimal 对象的 int/float 值:

      """ assume d is your decimal object """

      serializable_d = int(d) # or float(d)

      d_json = json.dumps(d)

      1. 您可以将simplejson 添加到您的requirements.txt,它现在支持序列化小数。它是包含的 json 模块的直接替代品。
      import simplejson as json # instead of import json
      

      您的其余代码的工作方式相同。如果您需要进一步的帮助,请发表评论。

      【讨论】:

      • 小数对象的存在是为了准确。转换为浮动可能会增加不确定性。在将 Decimal 转换为另一种类型之前,我会使用字符串值。
      • True,并且json序列化会自动将值转换为字符串。但是,尽管如此,
      • 如果你知道它精确到美分,你可以通过将它放大 100 作为小数将它精确地发送到 js,然后截断为 bigint,只要你保持 .toFixed(2),它会按预期工作。
      • 然后下一个异常::日期类型的对象不是 JSON 可序列化的。
      【解决方案3】:

      创建一个函数来处理TypeError 并使用json.dumpsdefault 参数来设置它。这避免了TypeError: Object of type Decimal is not JSON serializable

      https://docs.python.org/3/library/json.html

      如果指定,默认应该是一个被调用的函数 否则无法序列化的对象。它应该返回一个 JSON 对象的可编码版本或引发 TypeError。如果不 指定,引发 TypeError。

      json_utils.py:

      import decimal
      import json
      
      
      def dumps(item: dict) -> str:
          return json.dumps(item, default=default_type_error_handler)
      
      
      def default_type_error_handler(obj):
          if isinstance(obj, decimal.Decimal):
              return int(obj)
          raise TypeError
      

      test_json_utils.py:

      import json
      from decimal import Decimal
      from commons import json_utils
      
      
      def test_different_data_types():
          # Prepare data
          item = {
              "a-string": "lorem",
              "a-boolean": True,
              "a-number": 4711,
              "a-decimal-object": Decimal(4711)  # Used by dynamoDb boto3 client
          }
      
          # Execute
          item_as_json = json_utils.dumps(item)
      
          # Assert
          item_back_to_dict = json.loads(item_as_json)
          assert item_back_to_dict == item
      

      【讨论】:

        猜你喜欢
        • 2023-03-15
        • 2022-09-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 2021-03-11
        • 2021-07-04
        • 2021-12-10
        • 1970-01-01
        相关资源
        最近更新 更多