나는 Decimal('3.9')
객체의 일부를 가지고 있으며 이것을 JSON 문자열로 인코딩하고 싶습니다.{'x': 3.9}
. 나는 클라이언트 측의 정밀도에 관심이 없으므로 플로트가 좋습니다.
이것을 직렬화하는 좋은 방법이 있습니까? JSONDecoder는 Decimal 객체를 허용하지 않으며 사전에 float로 변환하면 {'x': 3.8999999999999999}
잘못된 결과를 낳으며 대역폭을 크게 낭비하게됩니다.
답변
서브 클래 싱은 json.JSONEncoder
어떻습니까?
class DecimalEncoder(json.JSONEncoder):
def _iterencode(self, o, markers=None):
if isinstance(o, decimal.Decimal):
# wanted a simple yield str(o) in the next line,
# but that would mean a yield on the line with super(...),
# which wouldn't work (see my comment below), so...
return (str(o) for o in [o])
return super(DecimalEncoder, self)._iterencode(o, markers)
그런 다음 다음과 같이 사용하십시오.
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)
답변
Simplejson 2.1 이상은 기본적으로 Decimal 유형을 지원합니다.
>>> json.dumps(Decimal('3.9'), use_decimal=True)
'3.9'
참고 use_decimal
입니다 True
기본적으로 :
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=True,
namedtuple_as_object=True, tuple_as_array=True,
bigint_as_string=False, sort_keys=False, item_sort_key=None,
for_json=False, ignore_nan=False, **kw):
그래서:
>>> json.dumps(Decimal('3.9'))
'3.9'
이 기능이 표준 라이브러리에 포함되기를 바랍니다.
답변
Python 2.6.5를 실행하는 웹 서버에서 Michał Marczyk의 답변을 시도했지만 정상적으로 작동했음을 모든 사람에게 알리고 싶습니다. 그러나 Python 2.7로 업그레이드하면 작동이 중지되었습니다. Decimal 객체를 인코딩하는 방법을 생각해 보았습니다. 이것은 내가 생각해 낸 것입니다.
import decimal
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return float(o)
return super(DecimalEncoder, self).default(o)
파이썬 2.7에 문제가있는 사람이라면 누구나 도움이 될 것입니다. 나는 그것을 테스트했고 잘 작동하는 것 같다. 누군가 내 솔루션의 버그를 발견하거나 더 나은 방법을 찾은 경우 알려주십시오.
답변
Python 2.7.11, 플라스크 연금술 ( ‘db.decimal’유형) 및 Flask Marshmallow ( ‘instant’serializer 및 deserializer의 경우)를 사용하는 Flask 앱에서 GET 또는 POST를 수행 할 때 마다이 오류가 발생했습니다. . serializer 및 deserializer가 Decimal 형식을 JSON 식별 가능한 형식으로 변환하지 못했습니다.
“pip install simplejson”을 수행 한 다음
import simplejson as json
시리얼 라이저와 디시리얼라이저가 다시 시작됩니다. 나는 아무것도하지 않았다 … DEciamls는 ‘234.00’플로트 형식으로 표시됩니다.
답변
GAE 2.7에서 simplejson에서 내장 json으로 전환하려고 시도했으며 소수에 문제가 있습니다. default가 str (o)를 반환하면 _iterencode가 default 결과로 _iterencode를 호출하기 때문에 따옴표가 있었고 float (o)는 후행 0을 제거합니다.
기본값이 float (또는 추가 서식없이 repr을 호출하는 클래스)에서 상속하고 사용자 정의 __repr__ 메소드가있는 클래스의 객체를 반환하면 원하는대로 작동하는 것 같습니다.
import json
from decimal import Decimal
class fakefloat(float):
def __init__(self, value):
self._value = value
def __repr__(self):
return str(self._value)
def defaultencode(o):
if isinstance(o, Decimal):
# Subclass float with custom repr?
return fakefloat(o)
raise TypeError(repr(o) + " is not JSON serializable")
json.dumps([10.20, "10.20", Decimal('10.20')], default=defaultencode)
'[10.2, "10.20", 10.20]'
답변
기본 옵션이 누락되었으므로 다음 사람 / 공을 위해 추가 할 것입니다.
Django 1.7.x부터는에서 DjangoJSONEncoder
얻을 수 있는 내장 기능 이 있습니다 django.core.serializers.json
.
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict
model_instance = YourModel.object.first()
model_dict = model_to_dict(model_instance)
json.dumps(model_dict, cls=DjangoJSONEncoder)
프레스토 악장!
답변
내 $ .02!
웹 서버에 대한 수많은 데이터를 직렬화하기 때문에 JSON 인코더를 확장합니다. 좋은 코드가 있습니다. 그것은 당신이 느끼는 거의 모든 데이터 형식으로 쉽게 확장 가능하며 3.9를"thing": 3.9
JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_newdefault(self, o):
if isinstance(o, UUID): return str(o)
if isinstance(o, datetime): return str(o)
if isinstance(o, time.struct_time): return datetime.fromtimestamp(time.mktime(o))
if isinstance(o, decimal.Decimal): return str(o)
return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_newdefault
내 인생을 훨씬 더 쉽게 만듭니다 …