我有一个包含大量数组数据的大字典:
d = {'something': {'else': 'x'}, 'longnumbers': [1,2,3,4,54,6,67,7,7,8,8,8,6,4,3,3,5,6,7,4,3,5,6,54]}
真正的字典有更多的键和嵌套的结构。当我使用json.dump
而没有indent
时,我得到一个不可读的紧凑的单行输出。当我设置indent
时,它会在每个分隔符后面添加换行符,包括数组。
数值数组很长,最终结果如下:
"longnumbers": [
1,
2,
3,
4,
54,
6,
67,
7,
7,
8,
8,
8,
6,
4,
3,
3,
5,
6,
7,
4,
3,
5,
6,
54
],
有没有办法获得带有缩进级别的漂亮打印的JSON,但是没有在数组元素之后放置换行符?对于上面的例子,我想要这样的事情:
{
"longnumbers": [1, 2, 3, 4, 54, 6, 67, 7, 7, 8, 8, 8, 6, 4, 3, 3, 5, 6, 7, 4, 3, 5, 6, 54],
"something": {
"else": "x"
}
}
答案 0 :(得分:9)
我最后只编写了自己的JSON序列化程序:
import numpy
INDENT = 3
SPACE = " "
NEWLINE = "\n"
def to_json(o, level=0):
ret = ""
if isinstance(o, dict):
ret += "{" + NEWLINE
comma = ""
for k,v in o.iteritems():
ret += comma
comma = ",\n"
ret += SPACE * INDENT * (level+1)
ret += '"' + str(k) + '":' + SPACE
ret += to_json(v, level + 1)
ret += NEWLINE + SPACE * INDENT * level + "}"
elif isinstance(o, basestring):
ret += '"' + o + '"'
elif isinstance(o, list):
ret += "[" + ",".join([to_json(e, level+1) for e in o]) + "]"
elif isinstance(o, bool):
ret += "true" if o else "false"
elif isinstance(o, int):
ret += str(o)
elif isinstance(o, float):
ret += '%.7g' % o
elif isinstance(o, numpy.ndarray) and numpy.issubdtype(o.dtype, numpy.integer):
ret += "[" + ','.join(map(str, o.flatten().tolist())) + "]"
elif isinstance(o, numpy.ndarray) and numpy.issubdtype(o.dtype, numpy.inexact):
ret += "[" + ','.join(map(lambda x: '%.7g' % x, o.flatten().tolist())) + "]"
elif o is None:
ret += 'null'
else:
raise TypeError("Unknown type '%s' for json serialization" % str(type(o)))
return ret
答案 1 :(得分:2)
嗯,到目前为止,应该确实是为两种不同的JSON容器类型指定不同的缩进的选项。如果要与核心Python JSON库保持兼容,另一种方法是重写该库中负责处理_make_iterencode()
的函数(当前为indent
)。
在reimplementation of _make_iterencode()处有裂缝。仅需更改几个lines即可使用indent
选项,也可以选择使用元组(hash-indent, array-indent)
。但不幸的是,必须替换整个_make_iterencode()
,事实证明它非常大且分解得很差。无论如何,以下适用于3.4-3.6的作品:
import sys
import json
dat = {"b": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "a": 1, "c": "x"}
indent = 2
print(json.dumps(dat, indent=indent))
if sys.version_info.major == 3 and 4 <= sys.version_info.minor <= 6:
import _make_iterencode
json.encoder._make_iterencode = _make_iterencode._make_iterencode
indent = (2, None)
print(json.dumps(dat, indent=indent))
给予:
{
"c": "x",
"a": 1,
"b": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
]
}
{
"c": "x",
"a": 1,
"b": [1,2,3,4,5,6,7,8,9,10]
}
答案 2 :(得分:2)
@jterrace的答案是针对Python 2编写的,此后由于更改了类型而不再支持Python 3。因此,在对他的回答给予应有的肯定之后,我对它进行了一些微调,以方便我个人使用并与Python 3兼容,包括对列表中元组的支持:
import numpy
INDENT = 3
SPACE = " "
NEWLINE = "\n"
# Changed basestring to str, and dict uses items() instead of iteritems().
def to_json(o, level=0):
ret = ""
if isinstance(o, dict):
ret += "{" + NEWLINE
comma = ""
for k, v in o.items():
ret += comma
comma = ",\n"
ret += SPACE * INDENT * (level + 1)
ret += '"' + str(k) + '":' + SPACE
ret += to_json(v, level + 1)
ret += NEWLINE + SPACE * INDENT * level + "}"
elif isinstance(o, str):
ret += '"' + o + '"'
elif isinstance(o, list):
ret += "[" + ",".join([to_json(e, level + 1) for e in o]) + "]"
# Tuples are interpreted as lists
elif isinstance(o, tuple):
ret += "[" + ",".join(to_json(e, level + 1) for e in o) + "]"
elif isinstance(o, bool):
ret += "true" if o else "false"
elif isinstance(o, int):
ret += str(o)
elif isinstance(o, float):
ret += '%.7g' % o
elif isinstance(o, numpy.ndarray) and numpy.issubdtype(o.dtype, numpy.integer):
ret += "[" + ','.join(map(str, o.flatten().tolist())) + "]"
elif isinstance(o, numpy.ndarray) and numpy.issubdtype(o.dtype, numpy.inexact):
ret += "[" + ','.join(map(lambda x: '%.7g' % x, o.flatten().tolist())) + "]"
elif o is None:
ret += 'null'
else:
raise TypeError("Unknown type '%s' for json serialization" % str(type(o)))
return ret