问题
Consider the following input in a financial application, where precision matters:
{ "value": 3.8 }
And the following AWS Lambda function:
from decimal import Decimal
def lambda_handler(event, context):
value = event['value']
print(Decimal(value))
The output is: 3.79999999999999982236431605997495353221893310546875
because Python parsed the number in the JSON into a float, which can't precisely store 3.8.
I know that I can serialize event
back to a string and then instruct the parser to use Decimal (this is from the DynamoDB Python docs):
import json
def lambda_handler(event, context):
parsed = json.loads(json.dumps(event), parse_float=Decimal)
print(Decimal(parsed['value']))
But that feels like a hack. Is there some way to control the deserialization in the first place so that event
prefers Decimal to float?
回答1:
Update: There is nothing wrong with your current solution.
There is no float
to str
to decimal.Decimal
round-trip.
As the docs explain (my emphasis):
parse_float, if specified, will be called with the string of every JSON float to be decoded. By default, this is equivalent to float(num_str). This can be used to use another datatype or parser for JSON floats (e.g. decimal.Decimal).
Initial answer below
Passing a float
value to decimal.Decimal
does not ensure the precision you require. This is because, by its nature, float
is not stored as a decimal but in binary.
This can be alleviated if you are able to pass string inputs into decimal.Decimal
:
from decimal import Decimal
res1 = Decimal(3.8)*Decimal(10)
res2 = Decimal('3.8')*Decimal('10')
print(res1) # 37.99999999999999822364316060
print(res2) # 38.0
So one solution would be to ensure you store / read in JSON numeric data as strings instead of floats.
Be careful, an implementation as below may work but relies on str
doing a particular job, i.e. rounding a float
correctly for decimal representation.
def lambda_handler(event):
value = event['value']
print(Decimal(str(value)))
lambda_handler({"value": 3.8}) # 3.8
来源:https://stackoverflow.com/questions/50282080/decimal-in-input-json-to-python-3-lambda-function