python JSON数组换行符

时间:2012-04-10 22:39:50

标签: python json

我有一个包含大量数组数据的大字典:

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"
  }
}

3 个答案:

答案 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