类型 'Decimal' 的对象不可 JSON 序列化



Lambda执行失败,状态为200,原因是客户函数错误:"Decimal"类型的对象不是JSON可序列化的

我在下面的链接中浏览了所有现有的解决方案,但没有任何效果。我做错了什么?:Python JSON序列化Decimal对象

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)

下面是一个扩展JSONEncoder以处理json文档中指定的Decimal类型的示例

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,将在不依赖外部封装的情况下保持良好的精度。

似乎有两个选项:

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

""" 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

您的代码的其余部分也将正常工作。如果您需要进一步的帮助,请留言。

创建一个函数来处理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

最新更新