我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
当前回答
基于stdOrgnlDave的答案,我已经定义了这个包装器,它可以被可选的类型调用,所以编码器将只适用于项目中的某些类型。我相信工作应该在你的代码中完成,而不是使用这个“默认”编码器,因为“显式比隐式更好”,但我知道使用这将节省你的一些时间。: -)
import time
import json
import decimal
from uuid import UUID
from datetime import datetime
def JSONEncoder_newdefault(kind=['uuid', 'datetime', 'time', 'decimal']):
'''
JSON Encoder newdfeault is a wrapper capable of encoding several kinds
Use it anywhere on your code to make the full system to work with this defaults:
JSONEncoder_newdefault() # for everything
JSONEncoder_newdefault(['decimal']) # only for Decimal
'''
JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_wrapped(self, o):
'''
json.JSONEncoder.default = JSONEncoder_newdefault
'''
if ('uuid' in kind) and isinstance(o, uuid.UUID):
return str(o)
if ('datetime' in kind) and isinstance(o, datetime):
return str(o)
if ('time' in kind) and isinstance(o, time.struct_time):
return datetime.fromtimestamp(time.mktime(o))
if ('decimal' in kind) and isinstance(o, decimal.Decimal):
return str(o)
return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_wrapped
# Example
if __name__ == '__main__':
JSONEncoder_newdefault()
其他回答
我想让每个人都知道,我在运行Python 2.6.5的网络服务器上尝试了michaowarmarczyk的答案,它工作得很好。然而,我升级到Python 2.7,它停止工作了。我试着想一些方法来编码十进制对象,这就是我想到的:
import decimal
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.防止舍入错误。
希望这能帮助任何在使用Python 2.7时遇到问题的人。我测试过了,它似乎工作得很好。如果有人在我的解决方案中注意到任何错误或提出了更好的方法,请告诉我。
使用的例子:
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
这个问题很老了,但是对于大多数用例,Python3中似乎有一个更好、更简单的解决方案:
number = Decimal(0.55)
converted_number = float(number) # Returns: 0.55 (as type float)
你可以把Decimal转换成float。
十进制不适合通过以下方式进行转换:
浮子由于精度问题 由于openapi的限制
我们仍然需要直接十进制到一个数字json序列化。
下面是@tesdal的fakfloat解决方案的扩展(在v3.5.2rc1中关闭)。 它使用fakestr + monkeypatching来避免引号和小数的“浮动”。
import json.encoder
from decimal import Decimal
def encode_fakestr(func):
def wrap(s):
if isinstance(s, fakestr):
return repr(s)
return func(s)
return wrap
json.encoder.encode_basestring = encode_fakestr(json.encoder.encode_basestring)
json.encoder.encode_basestring_ascii = encode_fakestr(json.encoder.encode_basestring_ascii)
class fakestr(str):
def __init__(self, value):
self._value = value
def __repr__(self):
return str(self._value)
class DecimalJsonEncoder(json.encoder.JSONEncoder):
def default(self, o):
if isinstance(o, Decimal):
return fakestr(o)
return super().default(o)
json.dumps([Decimal('1.1')], cls=DecimalJsonEncoder)
[1.1]
我不明白为什么python开发人员强迫我们在不适合使用浮点数的地方使用浮点数。
基于stdOrgnlDave的答案,我已经定义了这个包装器,它可以被可选的类型调用,所以编码器将只适用于项目中的某些类型。我相信工作应该在你的代码中完成,而不是使用这个“默认”编码器,因为“显式比隐式更好”,但我知道使用这将节省你的一些时间。: -)
import time
import json
import decimal
from uuid import UUID
from datetime import datetime
def JSONEncoder_newdefault(kind=['uuid', 'datetime', 'time', 'decimal']):
'''
JSON Encoder newdfeault is a wrapper capable of encoding several kinds
Use it anywhere on your code to make the full system to work with this defaults:
JSONEncoder_newdefault() # for everything
JSONEncoder_newdefault(['decimal']) # only for Decimal
'''
JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_wrapped(self, o):
'''
json.JSONEncoder.default = JSONEncoder_newdefault
'''
if ('uuid' in kind) and isinstance(o, uuid.UUID):
return str(o)
if ('datetime' in kind) and isinstance(o, datetime):
return str(o)
if ('time' in kind) and isinstance(o, time.struct_time):
return datetime.fromtimestamp(time.mktime(o))
if ('decimal' in kind) and isinstance(o, decimal.Decimal):
return str(o)
return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_wrapped
# Example
if __name__ == '__main__':
JSONEncoder_newdefault()
在我的Flask应用程序中,它使用python 2.7.11, Flask alchemy(具有'db.decimal'类型)和Flask Marshmallow(用于'即时'序列化器和反序列化器),我有这个错误,每次我做GET或POST。序列化器和反序列化器未能将十进制类型转换为任何可识别的JSON格式。
然后,我做了一个“pip install simplejson” 只要加上
import simplejson as json
序列化器和反序列化器又开始工作了。我什么也没做…… 十进制显示为'234.00'浮点格式。