Skip to content

Instantly share code, notes, and snippets.

@odony
Last active July 23, 2021 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save odony/5269a695545902e7e23e761e20a9ec8c to your computer and use it in GitHub Desktop.
Save odony/5269a695545902e7e23e761e20a9ec8c to your computer and use it in GitHub Desktop.
Python 3 JSON serialization of floats with chosen precision
import json
import decimal
import odoo
from odoo.tools import float_utils
from decimal import Decimal
# Version 0: BROKEN because float_round does not return the float with the shortest
# representation, so it will serialize as 211.70000000000002.
d = {'foo': float_utils.float_round(211.7, 1)}
print(json.dumps(d))
# {"foo": 211.70000000000002}
# Version 1: rely the Python 2.7/3.1 "spec" that says that native float __repr__(f) will
# always use the shortest representation that rounds back to f. By rounding first with
# float_repr we choose the desired precision, and hope for the best.
d = {'foo': float(float_utils.float_repr(211.7, 1))}
print(json.dumps(d))
# {"foo": 211.7}
# Version 2: hold the float value in a Decimal instance to hook it up with a
# custom encoder, and then use a fake float type to serialize it as a string.
class number_str1(float):
def __init__(self, o):
self.o = o
def __repr__(self):
return str(self.o)
def __float__(self):
return self
class MyEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return number_str1(o)
return super().default(o)
d = {'foo': Decimal(float_utils.float_repr(211.7, 1))}
print(json.dumps(d, cls=MyEncoder))
# {"foo": 211.7}
# Version 3: skip the Decimal wrapper and directly use a fake float type that
# holds an exact string representation.
class float_string(float):
def __init__(self, fstr):
self.o = fstr
def __repr__(self):
return self.o
def __float__(self):
return self
d = {'foo': float_string(float_utils.float_repr(211.7, 1))}
print(json.dumps(d))
# {"foo": 211.7}
@Sukonnik-Illia
Copy link

Sukonnik-Illia commented Jan 13, 2021

My decision for float format without changing objects which we pass to the function.
works for Python3
https://gist.github.com/Sukonnik-Illia/ed9b2bec1821cad437d1b8adb17406a3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment