Python 3,不需要猴子补丁: import json def round_floats(o): if isinstance(o, float): return round(o, 2) if isinstance(o, dict): return {k: round_floats(v) for k, v in o.items()} if isinstance(o, (list, tuple)): return [round_floats(x) for x in o] return o json.dumps(round_floats([23.63437, 23.93437, 23.842347]))

Python 3,不需要猴子补丁: import json def round_floats(o): if isinstance(o, float): return round(o, 2) if isinstance(o, dict): return {k: round_floats(v) for k, v in o.items()} if isinstance(o, (list, tuple)): return [round_floats(x) for x in o] return o json.dumps(round_floats([23.63437, 23.93437, 23.842347])),python,json,formatting,floating-point,Python,Json,Formatting,Floating Point,输出为: [23.63, 23.93, 23.84] 它复制数据,但带有四舍五入的浮点。我刚刚发布了一个小型Python库来解决这个问题。安装 pip install fjson 使用类似于json,并添加float\u格式参数: 导入数学 导入fjson 数据={a:1,“b:math.pi} 打印(fjson.dumps(数据,float_format=“.6e”,indent=2)) 使用numpy 如果您确实有很长的浮动,您可以使用numpy将它们正确地向上/向下舍入: 导入jso

输出为:

[23.63, 23.93, 23.84]
它复制数据,但带有四舍五入的浮点。

我刚刚发布了一个小型Python库来解决这个问题。安装

pip install fjson
使用类似于
json
,并添加
float\u格式
参数:

导入数学
导入fjson
数据={a:1,“b:math.pi}
打印(fjson.dumps(数据,float_format=“.6e”,indent=2))
使用numpy 如果您确实有很长的浮动,您可以使用numpy将它们正确地向上/向下舍入:

导入json
将numpy作为np导入
data=np.array([23.671234,23.97432,23.870123])
dumps(np.around(data,decimals=2.tolist())
'[23.67,23.97,23.87]

我这样做了:)请注意,我的代码中逗号后面总是有两位数字

>>> json_dumps_with_two_digit_float({'a': 1.0})
'{"a": 1.00}'
我的自定义功能:

from unittest.mock import patch
import json
# We need to ensure that c encoder will not be launched
@patch('json.encoder.c_make_encoder', None)
def json_dumps_with_two_digit_float(some_object):
    # saving original method
    of = json.encoder._make_iterencode
    def inner(*args, **kwargs):
        args = list(args)
        # fifth argument is float formater which will we replace
        args[4] = lambda o: '{:.2f}'.format(o)
        return of(*args, **kwargs)
    
    with patch('json.encoder._make_iterencode', wraps=inner):
        return json.dumps(some_object)

不要忘记在您的项目中创建一些测试,因为my func与python json模块实现密切相关,将来可能会进行更改。

此解决方案在使用python的C版json编码器的python 2.7中不起作用。但是您这样做,使用%.15g或%.12g之类的代码来代替%.3f。我在一位初级程序员的代码中发现了这段代码。如果没有被发现,这将产生一个非常严重但微妙的错误。请在此代码上放置一个警告,解释此猴子补丁的全球影响。完成后将其设置回原来的\u float\u repr=encoder.float\u repr
encoder.float\u repr=lambda o:format(o,.2f')
打印json.dumps(1.0001)
encoder.FLOAT\u REPR=original\u FLOAT\u REPR
正如其他人所指出的,至少在Python3.6+中,这已经不起作用了。在
23.67
中添加几个数字,看看
.2f
是如何不受尊重的。这些看起来像字符串,而不是数字。我喜欢这个解决方案;更好的集成,并与2.7兼容。因为我自己正在构建数据,所以我取消了
pretty_floats
函数,并将其简单地集成到我的其他代码中。在Python3中,它给出了“Map object is not JSON serializable”错误,但您可以通过
list(Map(pretty_floats,obj))解决将Map()转换为列表的问题
@Guglie:这是因为在Python 3中,map返回迭代器,而不是
列表
对我不起作用(Python 3.5.2,simplejson 3.16.0)。使用%.6g和[23.671234556,23.971234556,23.871234556]进行了尝试,它仍然会打印出整数。Python 2.6的另一种方法是使用JSONECODER.iterencode和模式匹配,希望这能使浮动的传递更加轻量级-我喜欢我们如何避免弄乱JSON类,因为JSON类很糟糕。谢谢,这真是一个很有帮助的建议。我不知道
parse\u float
kwarg!这里最简单的建议也适用于3.6。注意短语“不介意额外的CPU负载”。如果有大量数据要序列化,则绝对不要使用此解决方案。对我来说,仅添加这一项就让一个程序执行一个非平凡的计算所需的时间延长了3倍。如果您需要6位小数左右的精度,这将不起作用。看起来很整洁,但在Python 3.6上似乎不起作用。特别是,我在
json.encoder
模块中没有看到
FLOAT\u REPR
常量。内置的Python3 json包没有使用uuu REPR\uuu()。所以你需要在numpy ndarray中输入和输出FLOAT才能工作?
>>> import json
>>> json.encoder.FLOAT_REPR = lambda f: ("%.2f" % f)
>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
23.67
[23.67, 23.97, 23.87]
$ python
Python 2.5.4 (r254:67916, Jan 20 2009, 11:06:13) 
[GCC 4.2.1 (SUSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import simplejson
>>> simplejson.__version__
'2.0.9'
>>> simplejson._speedups
<module 'simplejson._speedups' from '/home/carlos/.python-eggs/simplejson-2.0.9-py2.5-linux-i686.egg-tmp/simplejson/_speedups.so'>
>>> simplejson.encoder.FLOAT_REPR = lambda f: ("%.2f" % f)
>>> simplejson.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
>>> simplejson.encoder.c_make_encoder = None
>>> simplejson.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
>>> 
[23.67, 23.97, 23.87]
>>> sys.version
'2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)]'
>>> json.dumps(1.0/3.0)
'0.3333333333333333'
>>> json.dumps(round(1.0/3.0, 2))
'0.33'
>>> sys.version
'2.6.6 (r266:84292, Dec 27 2010, 00:02:40) \n[GCC 4.4.5]'
>>> json.dumps(round(1.0/3.0, 2))
'0.33000000000000002'
>>> json.dumps(PrettyFloat(1.0 / 3.0, 4))
'0.3333'
import json
import math

class MyEncoder(json.JSONEncoder):
    "JSON encoder that renders floats to two decimal places"

    FLOAT_FRMT = '{0:.2f}'

    def floatstr(self, obj):
        return self.FLOAT_FRMT.format(obj)

    def _iterencode(self, obj, markers=None):
        # stl JSON lame override #1
        new_obj = obj
        if isinstance(obj, float):
            if not math.isnan(obj) and not math.isinf(obj):
                new_obj = self.floatstr(obj)
        return super(MyEncoder, self)._iterencode(new_obj, markers=markers)

    def _iterencode_dict(self, dct, markers=None):
        # stl JSON lame override #2
        new_dct = {}
        for key, value in dct.iteritems():
            if isinstance(key, float):
                if not math.isnan(key) and not math.isinf(key):
                    key = self.floatstr(key)
            new_dct[key] = value
        return super(MyEncoder, self)._iterencode_dict(new_dct, markers=markers)
>>> from tmp import MyEncoder
>>> enc = MyEncoder()
>>> enc.encode([23.67, 23.98, 23.87])
'[23.67, 23.98, 23.87]'
>>> import MyEncoder
>>> enc = MyEncoder()  
>>> enc.encode([23.67, 23.97, 23.87])
'["23.67", "23.97", "23.87"]'
import threading
from json import encoder

def FLOAT_REPR(f):
    """
    Serialize a float to a string, with a given number of digits
    """
    decimal_places = getattr(encoder.thread_local, 'decimal_places', 0)
    format_str = '%%.%df' % decimal_places
    return format_str % f

encoder.thread_local = threading.local()
encoder.FLOAT_REPR = FLOAT_REPR     

#As an example, call like this:
import json

encoder.thread_local.decimal_places = 1
json.dumps([1.56, 1.54]) #Should result in '[1.6, 1.5]'
def fix_floats(json, decimals=2, quote='"'):
    pattern = r'^((?:(?:"(?:\\.|[^\\"])*?")|[^"])*?)(-?\d+\.\d{'+str(decimals)+'}\d+)'
    pattern = re.sub('"', quote, pattern) 
    fmt = "%%.%df" % decimals
    n = 1
    while n:
        json, n = re.subn(pattern, lambda m: m.group(1)+(fmt % float(m.group(2)).rstrip('0')), json)
    return json
import json
json.encoder.FLOAT_REPR = lambda o: format(o, '.2f')

json.dumps([23.67, 23.97, 23.87]) #returns  '[23.67, 23.97, 23.87]'
import json
json.dumps([23.67, 23.9779, 23.87489])
# output is'[23.670000000000002, 23.977900000000002, 23.874890000000001]'

json.encoder.FLOAT_REPR = str
json.dumps([23.67, 23.9779, 23.87489])
# output is '[23.67, 23.9779, 23.87489]'
>>> json.dumps(json.loads(json.dumps([.333333333333, .432432]), parse_float=lambda x: round(float(x), 3)))
'[0.333, 0.432]'
import decimal
C = decimal.getcontext()

class decimal_formatted_float(float):
   def __repr__(self):
       s = str(C.create_decimal_from_float(self))
       if '.' in s: s = s.rstrip('0')
       return s

def convert_to_dff(elem):
    try:
        return elem.__class__(map(convert_to_dff, elem))
    except:
        if isinstance(elem, float):
            return decimal_formatted_float(elem)
        else:
            return elem
>>> import json
>>> li = [(1.2345,),(7.890123,4.567,890,890.)]
>>>
>>> decimal.getcontext().prec = 15
>>> dff_li = convert_to_dff(li)
>>> dff_li
[(1.2345,), (7.890123, 4.567, 890, 890)]
>>> json.dumps(dff_li)
'[[1.2345], [7.890123, 4.567, 890, 890]]'
>>>
>>> decimal.getcontext().prec = 3
>>> dff_li = convert_to_dff(li)
>>> dff_li
[(1.23,), (7.89, 4.57, 890, 890)]
>>> json.dumps(dff_li)
'[[1.23], [7.89, 4.57, 890, 890]]'
import json

def round_floats(o):
    if isinstance(o, float): return round(o, 2)
    if isinstance(o, dict): return {k: round_floats(v) for k, v in o.items()}
    if isinstance(o, (list, tuple)): return [round_floats(x) for x in o]
    return o


json.dumps(round_floats([23.63437, 23.93437, 23.842347]))
[23.63, 23.93, 23.84]
pip install fjson
{
  "a": 1,
  "b": 3.141593e+00
}
>>> json_dumps_with_two_digit_float({'a': 1.0})
'{"a": 1.00}'
from unittest.mock import patch
import json
# We need to ensure that c encoder will not be launched
@patch('json.encoder.c_make_encoder', None)
def json_dumps_with_two_digit_float(some_object):
    # saving original method
    of = json.encoder._make_iterencode
    def inner(*args, **kwargs):
        args = list(args)
        # fifth argument is float formater which will we replace
        args[4] = lambda o: '{:.2f}'.format(o)
        return of(*args, **kwargs)
    
    with patch('json.encoder._make_iterencode', wraps=inner):
        return json.dumps(some_object)