尝试使用 python boto 库插入浮点数时出现 DynamoDBNumberError
DynamoDBNumberError on trying to insert floating point number using python boto library
代码片段:
conn = dynamo_connect()
company = Table("companydb",connection=conn)
companyrecord = {'company-slug':'www-google-com12','founding-year':1991, 'randomlist' :[1,2,3,4,5], 'randomdict' : {'a':[1,2,3],'b':'something','randomnumber':10.55} }
company.put_item(data=companyrecord)
我收到以下错误:
File "C:\Python27\lib\site-packages\boto\dynamodb2\items.py", line 329, in prepare_full
final_data[key] = self._dynamizer.encode(value)
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 279, in encode
return {dynamodb_type: encoder(attr)}
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 335, in _encode_m
return dict([(k, self.encode(v)) for k, v in attr.items()])
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 279, in encode
return {dynamodb_type: encoder(attr)}
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 305, in _encode_n
raise DynamoDBNumberError(msg)
boto.dynamodb.exceptions.DynamoDBNumberError: BotoClientError: Inexact numeric for `10.55`
是的 GitHub 上已知 issues 与浮点数有关,可能有 2 个解决方法,首先,如果您愿意 table 存储 10.5
而不是10.55
,那么我猜它就可以正常工作,另一种方法是将浮点值存储为字符串或整数,然后在访问时对其进行调制。
所以你们选择了字符串部分然后你可以将它存储为 '10.55'
而不是 10.55
然后当你从 table 访问值时你可以简单地使用 float("10.55")
你就完成了。
另一种方法是将其存储为整数,首先选择一个精度值(比如 2 位小数)然后将 10.55
存储为 1055
(乘以 100,因为 2 位小数精度),在访问它时,您可以简单地使用 1055/100.0
,您将得到 10.55
。
Python3 提供 float.hex() / .fromhex() 将浮点数存储为字符串而不丢失精度:
Two methods support conversion to and from hexadecimal strings. Since Python’s floats are stored internally as binary numbers, converting a float to or from a decimal string usually involves a small rounding error. In contrast, hexadecimal strings allow exact representation and specification of floating-point numbers. This can be useful when debugging, and in numerical work.
如果您不想失去任何精度,这可能是@ZdaR 使用 str()
和 float()
进行转换的解决方案的替代方案。
[注意:我是新用户,无法对]发表评论
改用 Decimal(str(your_number))。
参见 https://github.com/boto/boto3/issues/665
如果您正在处理更大的集合并希望避免按记录处理转换十进制,这会有所帮助。
from decimal import Decimal
import json
changed_data = json.loads(json.dumps(data), parse_float=Decimal)
这是我通过覆盖 typeSerializer 插入浮点数的解决方案。
from boto3.dynamodb import types
from decimal import Decimal, localcontext
import re
class CustomSerializer(types.TypeSerializer):
def _is_number(self, value):
if isinstance(value, (int, Decimal, float)):
return True
return False
# Add float-specific serialization code
def _serialize_n(self, value):
if isinstance(value, float):
with localcontext(types.DYNAMODB_CONTEXT) as context:
stringify_val = str(value)
number = str(context.create_decimal(stringify_val))
return number
number = super(CustomSerializer, self)._serialize_n(value)
return number
serializer = CustomSerializer()
serialized_data = serializer.serialize(data)
以防万一它对某人有用。
我有这样的结构:
{
"hash_key": 1,
"range_key": 2,
"values": {
"valueA": 1.2,
"valueB": 2.1,
"valueC": 3.1,
"valueD": 4.1,
"valueE": 5.1,
"valueF": 6.1
}
}
我在一个名为 parameters 的对象中有这本字典
额外说明;我进行了此验证,因为并非所有时间我都收到值键:
values = parameters['values'] if 'values' in parameters else {}
if values: # So... this made the trick:
parameters['values'] = [{key: str(value)} for key, value in values.items()]
这种转变成就了作品。
我也在用
boto3.resource('dynamodb')
table = dynamo.Table(TABLE_NAME)
table.put_item(Item=parameters, ReturnValues='ALL_OLD')
完整的函数如下所示:
def create_item(parameters):
dynamo = boto3.resource('dynamodb')
table = dynamo.Table('your_table_name')
parameters['hash_key'] = str(parameters['hash_key'])
parameters['range_key'] = str(parameters['range_key'])
values = parameters['values'] if 'values' in parameters else {}
if values:
parameters['values'] = [{key: str(value)} for key, value in values.items()]
try:
response = table.put_item(Item=parameters, ReturnValues='ALL_OLD')
except ClientError as e:
response = e.response['Error']
# this is a local function to give format to the error
return create_response(response['Message'], response)
return response
不确定这是否是 tldr 案例,希望对您有所帮助 c:
您需要将浮点值解析为十进制
from datetime import datetime
from decimal import Decimal
decimal_value = Decimal(datetime.utcnow().timestamp())
代码片段:
conn = dynamo_connect()
company = Table("companydb",connection=conn)
companyrecord = {'company-slug':'www-google-com12','founding-year':1991, 'randomlist' :[1,2,3,4,5], 'randomdict' : {'a':[1,2,3],'b':'something','randomnumber':10.55} }
company.put_item(data=companyrecord)
我收到以下错误:
File "C:\Python27\lib\site-packages\boto\dynamodb2\items.py", line 329, in prepare_full
final_data[key] = self._dynamizer.encode(value)
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 279, in encode
return {dynamodb_type: encoder(attr)}
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 335, in _encode_m
return dict([(k, self.encode(v)) for k, v in attr.items()])
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 279, in encode
return {dynamodb_type: encoder(attr)}
File "C:\Python27\lib\site-packages\boto\dynamodb\types.py", line 305, in _encode_n
raise DynamoDBNumberError(msg)
boto.dynamodb.exceptions.DynamoDBNumberError: BotoClientError: Inexact numeric for `10.55`
是的 GitHub 上已知 issues 与浮点数有关,可能有 2 个解决方法,首先,如果您愿意 table 存储 10.5
而不是10.55
,那么我猜它就可以正常工作,另一种方法是将浮点值存储为字符串或整数,然后在访问时对其进行调制。
所以你们选择了字符串部分然后你可以将它存储为 '10.55'
而不是 10.55
然后当你从 table 访问值时你可以简单地使用 float("10.55")
你就完成了。
另一种方法是将其存储为整数,首先选择一个精度值(比如 2 位小数)然后将 10.55
存储为 1055
(乘以 100,因为 2 位小数精度),在访问它时,您可以简单地使用 1055/100.0
,您将得到 10.55
。
Python3 提供 float.hex() / .fromhex() 将浮点数存储为字符串而不丢失精度:
Two methods support conversion to and from hexadecimal strings. Since Python’s floats are stored internally as binary numbers, converting a float to or from a decimal string usually involves a small rounding error. In contrast, hexadecimal strings allow exact representation and specification of floating-point numbers. This can be useful when debugging, and in numerical work.
如果您不想失去任何精度,这可能是@ZdaR 使用 str()
和 float()
进行转换的解决方案的替代方案。
[注意:我是新用户,无法对
改用 Decimal(str(your_number))。 参见 https://github.com/boto/boto3/issues/665
如果您正在处理更大的集合并希望避免按记录处理转换十进制,这会有所帮助。
from decimal import Decimal
import json
changed_data = json.loads(json.dumps(data), parse_float=Decimal)
这是我通过覆盖 typeSerializer 插入浮点数的解决方案。
from boto3.dynamodb import types
from decimal import Decimal, localcontext
import re
class CustomSerializer(types.TypeSerializer):
def _is_number(self, value):
if isinstance(value, (int, Decimal, float)):
return True
return False
# Add float-specific serialization code
def _serialize_n(self, value):
if isinstance(value, float):
with localcontext(types.DYNAMODB_CONTEXT) as context:
stringify_val = str(value)
number = str(context.create_decimal(stringify_val))
return number
number = super(CustomSerializer, self)._serialize_n(value)
return number
serializer = CustomSerializer()
serialized_data = serializer.serialize(data)
以防万一它对某人有用。
我有这样的结构:
{
"hash_key": 1,
"range_key": 2,
"values": {
"valueA": 1.2,
"valueB": 2.1,
"valueC": 3.1,
"valueD": 4.1,
"valueE": 5.1,
"valueF": 6.1
}
}
我在一个名为 parameters 的对象中有这本字典 额外说明;我进行了此验证,因为并非所有时间我都收到值键:
values = parameters['values'] if 'values' in parameters else {}
if values: # So... this made the trick:
parameters['values'] = [{key: str(value)} for key, value in values.items()]
这种转变成就了作品。
我也在用
boto3.resource('dynamodb')
table = dynamo.Table(TABLE_NAME)
table.put_item(Item=parameters, ReturnValues='ALL_OLD')
完整的函数如下所示:
def create_item(parameters):
dynamo = boto3.resource('dynamodb')
table = dynamo.Table('your_table_name')
parameters['hash_key'] = str(parameters['hash_key'])
parameters['range_key'] = str(parameters['range_key'])
values = parameters['values'] if 'values' in parameters else {}
if values:
parameters['values'] = [{key: str(value)} for key, value in values.items()]
try:
response = table.put_item(Item=parameters, ReturnValues='ALL_OLD')
except ClientError as e:
response = e.response['Error']
# this is a local function to give format to the error
return create_response(response['Message'], response)
return response
不确定这是否是 tldr 案例,希望对您有所帮助 c:
您需要将浮点值解析为十进制
from datetime import datetime
from decimal import Decimal
decimal_value = Decimal(datetime.utcnow().timestamp())