Man*_*ron 89 python floating-point formatting json
我在python 2.6中使用标准的json模块来序列化浮点数列表.但是,我得到的结果如下:
>>> import json
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Run Code Online (Sandbox Code Playgroud)
我希望浮点数只用两位小数进行格式化.输出应如下所示:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
Run Code Online (Sandbox Code Playgroud)
我尝试过定义自己的JSON Encoder类:
class MyEncoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, float):
return format(obj, '.2f')
return json.JSONEncoder.encode(self, obj)
Run Code Online (Sandbox Code Playgroud)
这适用于唯一的浮动对象:
>>> json.dumps(23.67, cls=MyEncoder)
'23.67'
Run Code Online (Sandbox Code Playgroud)
但嵌套对象失败:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Run Code Online (Sandbox Code Playgroud)
我不想有外部依赖,所以我更喜欢坚持使用标准的json模块.
我怎样才能做到这一点?
Ale*_*lli 75
不幸的是,我相信你必须通过猴子修补来实现这一点(我认为这表明标准库json
包中存在设计缺陷).例如,这段代码:
import json
from json import encoder
encoder.FLOAT_REPR = lambda o: format(o, '.2f')
print json.dumps(23.67)
print json.dumps([23.67, 23.97, 23.87])
Run Code Online (Sandbox Code Playgroud)
发出:
23.67
[23.67, 23.97, 23.87]
Run Code Online (Sandbox Code Playgroud)
如你所愿.显然,应该有一种架构方式来覆盖,FLOAT_REPR
以便如果您希望浮动的每个表示都在您的控制之下; 但不幸的是,这不是json
包装的设计方式:-(.
小智 58
import simplejson
class PrettyFloat(float):
def __repr__(self):
return '%.15g' % self
def pretty_floats(obj):
if isinstance(obj, float):
return PrettyFloat(obj)
elif isinstance(obj, dict):
return dict((k, pretty_floats(v)) for k, v in obj.items())
elif isinstance(obj, (list, tuple)):
return map(pretty_floats, obj) # in Python3 do: list(map(pretty_floats, obj))
return obj
print simplejson.dumps(pretty_floats([23.67, 23.97, 23.87]))
Run Code Online (Sandbox Code Playgroud)
发射
[23.67, 23.97, 23.87]
Run Code Online (Sandbox Code Playgroud)
不需要monkeypatching.
Nel*_*son 26
如果您使用的是Python 2.7,一个简单的解决方案就是简单地将浮点数显式舍入到所需的精度.
>>> 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'
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为Python 2.7使浮点舍入更加一致.不幸的是,这在Python 2.6中不起作用:
>>> 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'
Run Code Online (Sandbox Code Playgroud)
上面提到的解决方案是2.6的解决方法,但没有一个是完全足够的.如果您的Python运行时使用C版本的JSON模块,则猴子修补json.encoder.FLOAT_REPR不起作用.Tom Wuttke的答案中的PrettyFloat类可用,但前提是%g编码适用于您的应用程序.%.15g有点神奇,它起作用,因为浮点精度是17位有效数字而%g不打印尾随零.
我花了一些时间尝试制作一个PrettyFloat,允许自定义每个数字的精度.就是这样的语法
>>> json.dumps(PrettyFloat(1.0 / 3.0, 4))
'0.3333'
Run Code Online (Sandbox Code Playgroud)
要做到这一点并不容易.继承浮动很尴尬.继承自Object并使用带有自己的default()方法的JSONEncoder子类应该可以工作,除了json模块似乎假设所有自定义类型都应序列化为字符串.即:你最终得到输出中的Javascript字符串"0.33",而不是数字0.33.可能有一种方法可以使这项工作,但它比它看起来更难.
Cla*_*ude 13
真的很不幸,dumps
不允许你做浮动任何事情.不过loads
.因此,如果您不介意额外的CPU负载,您可以通过编码器/解码器/编码器将其抛出并获得正确的结果:
>>> json.dumps(json.loads(json.dumps([.333333333333, .432432]), parse_float=lambda x: round(float(x), 3)))
'[0.333, 0.432]'
Run Code Online (Sandbox Code Playgroud)
如果您遇到Python 2.5或更早版本:如果安装了C加速,那么Monkey-patch技巧似乎不适用于原始的simplejson模块:
$ 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]'
>>>
Run Code Online (Sandbox Code Playgroud)
如果你实际上有很长的浮点数,你可以使用 numpy 正确地将它们向上/向下舍入:
import json
import numpy as np
data = np.array([23.671234, 23.97432, 23.870123])
json.dumps(np.around(data, decimals=2).tolist())
Run Code Online (Sandbox Code Playgroud)
'[23.67, 23.97, 23.87]'
您可以执行您需要执行的操作,但未记录:
>>> import json
>>> json.encoder.FLOAT_REPR = lambda f: ("%.2f" % f)
>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
Run Code Online (Sandbox Code Playgroud)
这是在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]))
Run Code Online (Sandbox Code Playgroud)
输出为:
[23.63, 23.93, 23.84]
Run Code Online (Sandbox Code Playgroud)
它复制数据,但具有四舍五入的浮点数。
我刚刚发布了fjson,一个小型 Python 库来解决这个问题。安装与
pip install fjson
Run Code Online (Sandbox Code Playgroud)
并像 一样使用json
,并添加参数float_format
:
pip install fjson
Run Code Online (Sandbox Code Playgroud)
{
"a": 1,
"b": 3.141593e+00
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
58998 次 |
最近记录: |