【问题标题】:How to prettyprint a JSON file?如何漂亮地打印 JSON 文件?
【发布时间】:2012-10-08 06:31:25
【问题描述】:

我有一个杂乱无章的 JSON 文件,我想把它打印出来。在 Python 中最简单的方法是什么?

我知道 PrettyPrint 需要一个“对象”,我认为它可以是一个文件,但我不知道如何传入一个文件。仅使用文件名是行不通的。

【问题讨论】:

  • 尝试使用 json.loads() 解析 JSON 并漂亮地打印结果字典。或者直接跳到 Python documentation for json漂亮打印 部分。
  • @Blender 如果你发布一个答案,我会给你信用......这可能会作为重复关闭,因为解决方案是相同的,但问题是不同的,所以也许不是。
  • 为什么不像@ed的链接那样<your_file.js python -mjson.tool
  • 我不认为它是重复的,因为从命令行进行漂亮打印与从 Python 以编程方式进行漂亮打印不同。投票重新开放。

标签: python json formatting pretty-print


【解决方案1】:

json module 已经在dumpdumps 函数中实现了一些基本的漂亮打印,其中indent 参数指定要缩进多少个空格:

>>> import json
>>>
>>> your_json = '["foo", {"bar":["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4, sort_keys=True))
[
    "foo", 
    {
        "bar": [
            "baz", 
            null, 
            1.0, 
            2
        ]
    }
]

要解析文件,请使用json.load():

with open('filename.txt', 'r') as handle:
    parsed = json.load(handle)

【讨论】:

  • 对于简单的漂亮打印,这也可以在没有显式解析的情况下工作:print json.dumps(your_json_string, indent=4)
  • 没有缩进,你只会得到一行丑陋的文字,这就是我来这里的原因。
  • 这类似于 JavaScript var str = JSON.stringify(obj, null, 4); 此处讨论的 stackoverflow.com/questions/4810841/…
  • @Peterino,如果没有显式解析,它就无法工作。它打印一个转义行
  • 谢谢 - 这被证明是非常有用的!
【解决方案2】:

您可以使用内置模块pprint (https://docs.python.org/3.9/library/pprint.html)

如何读取带有 json 数据的文件并打印出来。

import json
import pprint

json_data = None
with open('file_name.txt', 'r') as f:
    data = f.read()
    json_data = json.loads(data)

print(json_data)
{"firstName": "John", "lastName": "Smith", "isAlive": "true", "age": 27, "address": {"streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100"}, 'children': []}

pprint.pprint(json_data)
{'address': {'city': 'New York',
             'postalCode': '10021-3100',
             'state': 'NY',
             'streetAddress': '21 2nd Street'},
 'age': 27,
 'children': [],
 'firstName': 'John',
 'isAlive': True,
 'lastName': 'Smith'}

输出不是有效的json,因为pprint使用单引号而json规范需要双引号。

如果你想将漂亮打印格式的 json 重写为文件,你必须使用pprint.pformat

pretty_print_json = pprint.pformat(json_data).replace("'", '"')

with open('file_name.json', 'w') as f:
    f.write(pretty_print_json)

【讨论】:

  • 这个问题是 pprint 将使用单引号和双引号互换,但 json 只需要双引号,所以你的 pprint json 可能不再解析为有效的 json。
  • 可以,但只是输出一个json文件。不采取输出并将其再次写入文件。
  • 问题专门说要漂亮地打印一个 json 文件,而不是 json 文件的 python 表示
  • @DanielFarrell 你是对的。谢谢。我更新了我的答案。
【解决方案3】:

希望这对其他人有所帮助。

如果出现无法 json 序列化的错误,上述答案将不起作用。如果您只想保存它以便人类可读,那么您需要在字典的所有非字典元素上递归调用字符串。如果您想稍后加载它,然后将其保存为 pickle 文件,然后加载它(例如 torch.save(obj, f) 工作正常)。

这对我有用:

#%%

def _to_json_dict_with_strings(dictionary):
    """
    Convert dict to dict with leafs only being strings. So it recursively makes keys to strings
    if they are not dictionaries.

    Use case:
        - saving dictionary of tensors (convert the tensors to strins!)
        - saving arguments from script (e.g. argparse) for it to be pretty

    e.g.

    """
    if type(dictionary) != dict:
        return str(dictionary)
    d = {k: _to_json_dict_with_strings(v) for k, v in dictionary.items()}
    return d

def to_json(dic):
    import types
    import argparse

    if type(dic) is dict:
        dic = dict(dic)
    else:
        dic = dic.__dict__
    return _to_json_dict_with_strings(dic)

def save_to_json_pretty(dic, path, mode='w', indent=4, sort_keys=True):
    import json

    with open(path, mode) as f:
        json.dump(to_json(dic), f, indent=indent, sort_keys=sort_keys)

def my_pprint(dic):
    """

    @param dic:
    @return:

    Note: this is not the same as pprint.
    """
    import json

    # make all keys strings recursively with their naitve str function
    dic = to_json(dic)
    # pretty print
    pretty_dic = json.dumps(dic, indent=4, sort_keys=True)
    print(pretty_dic)
    # print(json.dumps(dic, indent=4, sort_keys=True))
    # return pretty_dic

import torch
# import json  # results in non serializabe errors for torch.Tensors
from pprint import pprint

dic = {'x': torch.randn(1, 3), 'rec': {'y': torch.randn(1, 3)}}

my_pprint(dic)
pprint(dic)

输出:

{
    "rec": {
        "y": "tensor([[-0.3137,  0.3138,  1.2894]])"
    },
    "x": "tensor([[-1.5909,  0.0516, -1.5445]])"
}
{'rec': {'y': tensor([[-0.3137,  0.3138,  1.2894]])},
 'x': tensor([[-1.5909,  0.0516, -1.5445]])}

我不知道为什么返回字符串然后打印它不起作用,但似乎您必须将转储直接放在打印语句中。请注意pprint,因为它已经被建议已经工作了。请注意,并非所有对象都可以使用dict(dic) 转换为字典,这就是为什么我的一些代码会检查这种情况。

上下文:

我想保存 pytorch 字符串,但一直报错:

TypeError: tensor is not JSON serializable

所以我编写了上面的代码。请注意,是的,在 pytorch 中您使用 torch.save 但泡菜文件不可读。查看此相关帖子:https://discuss.pytorch.org/t/typeerror-tensor-is-not-json-serializable/36065/3


PPrint 也有缩进参数,但我不喜欢它的外观:

    pprint(stats, indent=4, sort_dicts=True)

输出:

{   'cca': {   'all': {'avg': tensor(0.5132), 'std': tensor(0.1532)},
               'avg': tensor([0.5993, 0.5571, 0.4910, 0.4053]),
               'rep': {'avg': tensor(0.5491), 'std': tensor(0.0743)},
               'std': tensor([0.0316, 0.0368, 0.0910, 0.2490])},
    'cka': {   'all': {'avg': tensor(0.7885), 'std': tensor(0.3449)},
               'avg': tensor([1.0000, 0.9840, 0.9442, 0.2260]),
               'rep': {'avg': tensor(0.9761), 'std': tensor(0.0468)},
               'std': tensor([5.9043e-07, 2.9688e-02, 6.3634e-02, 2.1686e-01])},
    'cosine': {   'all': {'avg': tensor(0.5931), 'std': tensor(0.7158)},
                  'avg': tensor([ 0.9825,  0.9001,  0.7909, -0.3012]),
                  'rep': {'avg': tensor(0.8912), 'std': tensor(0.1571)},
                  'std': tensor([0.0371, 0.1232, 0.1976, 0.9536])},
    'nes': {   'all': {'avg': tensor(0.6771), 'std': tensor(0.2891)},
               'avg': tensor([0.9326, 0.8038, 0.6852, 0.2867]),
               'rep': {'avg': tensor(0.8072), 'std': tensor(0.1596)},
               'std': tensor([0.0695, 0.1266, 0.1578, 0.2339])},
    'nes_output': {   'all': {'avg': None, 'std': None},
                      'avg': tensor(0.2975),
                      'rep': {'avg': None, 'std': None},
                      'std': tensor(0.0945)},
    'query_loss': {   'all': {'avg': None, 'std': None},
                      'avg': tensor(12.3746),
                      'rep': {'avg': None, 'std': None},
                      'std': tensor(13.7910)}}

比较:

{
    "cca": {
        "all": {
            "avg": "tensor(0.5144)",
            "std": "tensor(0.1553)"
        },
        "avg": "tensor([0.6023, 0.5612, 0.4874, 0.4066])",
        "rep": {
            "avg": "tensor(0.5503)",
            "std": "tensor(0.0796)"
        },
        "std": "tensor([0.0285, 0.0367, 0.1004, 0.2493])"
    },
    "cka": {
        "all": {
            "avg": "tensor(0.7888)",
            "std": "tensor(0.3444)"
        },
        "avg": "tensor([1.0000, 0.9840, 0.9439, 0.2271])",
        "rep": {
            "avg": "tensor(0.9760)",
            "std": "tensor(0.0468)"
        },
        "std": "tensor([5.7627e-07, 2.9689e-02, 6.3541e-02, 2.1684e-01])"
    },
    "cosine": {
        "all": {
            "avg": "tensor(0.5945)",
            "std": "tensor(0.7146)"
        },
        "avg": "tensor([ 0.9825,  0.9001,  0.7907, -0.2953])",
        "rep": {
            "avg": "tensor(0.8911)",
            "std": "tensor(0.1571)"
        },
        "std": "tensor([0.0371, 0.1231, 0.1975, 0.9554])"
    },
    "nes": {
        "all": {
            "avg": "tensor(0.6773)",
            "std": "tensor(0.2886)"
        },
        "avg": "tensor([0.9326, 0.8037, 0.6849, 0.2881])",
        "rep": {
            "avg": "tensor(0.8070)",
            "std": "tensor(0.1595)"
        },
        "std": "tensor([0.0695, 0.1265, 0.1576, 0.2341])"
    },
    "nes_output": {
        "all": {
            "avg": "None",
            "std": "None"
        },
        "avg": "tensor(0.2976)",
        "rep": {
            "avg": "None",
            "std": "None"
        },
        "std": "tensor(0.0945)"
    },
    "query_loss": {
        "all": {
            "avg": "None",
            "std": "None"
        },
        "avg": "tensor(12.3616)",
        "rep": {
            "avg": "None",
            "std": "None"
        },
        "std": "tensor(13.7976)"
    }
}

【讨论】:

    【解决方案4】:

    我有一个类似的要求来转储 json 文件的内容以进行日志记录,这很简单:

    print(json.dumps(json.load(open(os.path.join('<myPath>', '<myjson>'), "r")), indent = 4 ))
    

    如果你经常使用它,那么把它放在一个函数中:

    def pp_json_file(path, file):
        print(json.dumps(json.load(open(os.path.join(path, file), "r")), indent = 4))
    

    【讨论】:

      【解决方案5】:

      您可以在命令行上执行此操作:

      python3 -m json.tool some.json
      

      (正如问题的评论中已经提到的,感谢@Kai Petzke 对python3 的建议)。

      实际上,就命令行上的 json 处理而言,python 并不是我最喜欢的工具。对于简单漂亮的打印是可以的,但如果你想操纵 json 它可能变得过于复杂。您很快就需要编写一个单独的脚本文件,您最终可能会得到键为 u"some-key" (python unicode) 的映射,这使得选择字段更加困难,并且并没有真正朝着漂亮的方向发展-打印。

      你也可以使用jq:

      jq . some.json
      

      你会得到颜色作为奖励(并且更容易扩展)。

      附录:在 cmets 中,一方面使用 jq 处理大型 JSON 文件,另一方面使用非常大的 jq 程序存在一些混淆。为了漂亮地打印由单个大型 JSON 实体组成的文件,实际限制是 RAM。对于包含单个真实数据数组的 2GB 文件的漂亮打印,漂亮打印所需的“最大驻留集大小”为 5GB(无论使用 jq 1.5 还是 1.6)。另请注意,jq 可以在 pip install jq 之后的 python 中使用。

      【讨论】:

      • JQ 很棒,但有一个最大限制,所以它对大文件没用。 (即炸毁处理 1.15mb 文件)github.com/stedolan/jq/issues/1041
      • 是的,伙计,当然,如果你正在编写超过 10K 行代码的 jq 过滤器,我认为你正在尝试像骑自行车去火星一样的东西。
      • lol :D @gismo-ranas 管道到文件的 json.tool 版本在大文件上非常有效;并且速度非常快。我喜欢 JQ,但格式化任何超出小型有效负载(您可以在大多数文本编辑器中执行)的内容都超出了它的范围:) 随机添加:json-generator.com 是制作测试数据的好工具
      • 或者只是:jq '' &lt; some.json
      • 其实我强烈推荐使用python3 -m json.tool &lt;IN &gt;OUT,因为这样可以保持 JSON dicts 中字段的原始顺序。 python 解释器版本 2 按字母升序对字段进行排序,这通常不是您想要的。
      【解决方案6】:

      它远非完美,但它可以胜任。

      data = data.replace(',"',',\n"')
      

      你可以改进它,添加缩进等等,但如果你只是想能够读取更干净的 json,这是要走的路。

      【讨论】:

      • AttributeError: 'dict' 对象没有属性 'replace'
      【解决方案7】:
      def saveJson(date,fileToSave):
          with open(fileToSave, 'w+') as fileToSave:
              json.dump(date, fileToSave, ensure_ascii=True, indent=4, sort_keys=True)
      

      它可以显示或保存到文件中。

      【讨论】:

        【解决方案8】:

        你可以试试pprintjson


        安装

        $ pip3 install pprintjson
        

        用法

        使用 pprintjson CLI 从文件中漂亮地打印 JSON。

        $ pprintjson "./path/to/file.json"
        

        使用 pprintjson CLI 从标准输入漂亮地打印 JSON。

        $ echo '{ "a": 1, "b": "string", "c": true }' | pprintjson
        

        使用 pprintjson CLI 从字符串中漂亮地打印 JSON。

        $ pprintjson -c '{ "a": 1, "b": "string", "c": true }'
        

        从缩进为 1 的字符串中漂亮地打印 JSON。

        $ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -i 1
        

        Pretty 从字符串打印 JSON 并将输出保存到文件 output.json。

        $ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -o ./output.json
        

        输出

        【讨论】:

        • 您的解决方案与import pprint pprint.pprint(json) 有何不同?
        • @CharlieParker 我认为它会生成一个有效的 json 文档,而不是 pprint 使用单引号而不是双引号
        【解决方案9】:

        使用 pprint:https://docs.python.org/3.6/library/pprint.html

        import pprint
        pprint.pprint(json)
        

        print()pprint.pprint() 相比

        print(json)
        {'feed': {'title': 'W3Schools Home Page', 'title_detail': {'type': 'text/plain', 'language': None, 'base': '', 'value': 'W3Schools Home Page'}, 'links': [{'rel': 'alternate', 'type': 'text/html', 'href': 'https://www.w3schools.com'}], 'link': 'https://www.w3schools.com', 'subtitle': 'Free web building tutorials', 'subtitle_detail': {'type': 'text/html', 'language': None, 'base': '', 'value': 'Free web building tutorials'}}, 'entries': [], 'bozo': 0, 'encoding': 'utf-8', 'version': 'rss20', 'namespaces': {}}
        
        pprint.pprint(json)
        {'bozo': 0,
         'encoding': 'utf-8',
         'entries': [],
         'feed': {'link': 'https://www.w3schools.com',
                  'links': [{'href': 'https://www.w3schools.com',
                             'rel': 'alternate',
                             'type': 'text/html'}],
                  'subtitle': 'Free web building tutorials',
                  'subtitle_detail': {'base': '',
                                      'language': None,
                                      'type': 'text/html',
                                      'value': 'Free web building tutorials'},
                  'title': 'W3Schools Home Page',
                  'title_detail': {'base': '',
                                   'language': None,
                                   'type': 'text/plain',
                                   'value': 'W3Schools Home Page'}},
         'namespaces': {},
         'version': 'rss20'}
        

        【讨论】:

        • pprint 没有生成有效的 JSON 文档。
        • @selurvedu 这是什么意思,为什么重要?
        • @CharlieParker 我希望他们的意思是知道你有一个有效的 JSON 文档非常有用。当然,您可以使用 json 模块来处理数据和字典键,它们与双引号或单引号字符串的工作方式相同,但有些工具,例如PostmanJSON Editor Online,都希望键和值被双引号(根据 JSON 规范)。在任何情况下,json.org 指定使用双引号,pprint 不会产生。例如。 pprint.pprint({"name": "Jane"}) 产生 {'name': 'Jane'}
        • @CharlieParker 例如上面结果中的'language': None,,应该是"language": null。注意null 和双引号。你所做的是漂亮地打印一个 Python 对象。
        • 是的,我就是这个意思。感谢您的澄清。 :-)
        【解决方案10】:

        我认为最好先解析json,避免出错:

        def format_response(response):
            try:
                parsed = json.loads(response.text)
            except JSONDecodeError:
                return response.text
            return json.dumps(parsed, ensure_ascii=True, indent=4)
        

        【讨论】:

          【解决方案11】:

          Pygmentize + Python json.tool = 带有语法高亮的漂亮打印

          Pygmentize 是一个杀手级工具。 See this.

          我将 python json.tool 与 pygmentize 结合起来

          echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l json
          

          pygmentize 安装说明见上面的链接。

          下图是一个演示:

          【讨论】:

          • 在您的示例中,-g 实际上不起作用;)由于输入来自标准输入,pygmentize 无法做出很好的猜测。您需要明确指定词法分析器:echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l json
          • @DenisTheMenace 当我创建这个示例图像时,它曾经在 2015 年工作。它现在似乎也无法在我的系统上运行。
          【解决方案12】:

          这是一个简单的示例,它在 Python 中以一种很好的方式将 JSON 漂亮地打印到控制台,而无需将 JSON 作为本地文件保存在您的计算机上:

          import pprint
          import json 
          from urllib.request import urlopen # (Only used to get this example)
          
          # Getting a JSON example for this example 
          r = urlopen("https://mdn.github.io/fetch-examples/fetch-json/products.json")
          text = r.read() 
          
          # To print it
          pprint.pprint(json.loads(text))
          

          【讨论】:

          • 我在 Python 3 中收到以下错误消息:“TypeError: JSON object must be str, not 'bytes'”
          【解决方案13】:

          为了能够从命令行漂亮地打印并能够控制缩进等,您可以设置一个类似于这样的别名:

          alias jsonpp="python -c 'import sys, json; print json.dumps(json.load(sys.stdin), sort_keys=True, indent=2)'"
          

          然后以下列方式之一使用别名:

          cat myfile.json | jsonpp
          jsonpp < myfile.json
          

          【讨论】:

            【解决方案14】:

            使用此函数,不必费力记住您的 JSON 是 str 还是 dict - 只需看看漂亮的打印:

            import json
            
            def pp_json(json_thing, sort=True, indents=4):
                if type(json_thing) is str:
                    print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents))
                else:
                    print(json.dumps(json_thing, sort_keys=sort, indent=indents))
                return None
            
            pp_json(your_json_string_or_dict)
            

            【讨论】:

              猜你喜欢
              • 2013-12-14
              • 1970-01-01
              • 2013-10-03
              • 2011-08-05
              • 1970-01-01
              相关资源
              最近更新 更多