如何在Python中漂亮地打印深度为~4的字典?我尝试用pprint()进行漂亮的打印,但它不起作用:

import pprint 
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)

我只是想要一个缩进(“\t”)为每个嵌套,这样我就会得到这样的东西:

key1
    value1
    value2
    key2
       value1
       value2

等。

我该怎么做呢?


当前回答

yapf的另一个选择:

from pprint import pformat
from yapf.yapflib.yapf_api import FormatCode

dict_example = {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5], '4': {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5]}}
dict_string = pformat(dict_example)
formatted_code, _ = FormatCode(dict_string)

print(formatted_code)

输出:

{
    '1': '1',
    '2': '2',
    '3': [1, 2, 3, 4, 5],
    '4': {
        '1': '1',
        '2': '2',
        '3': [1, 2, 3, 4, 5]
    }
}

其他回答

prettyformatter

免责声明:我是该软件包的作者。

有关与其他格式化程序的比较,请参阅其他格式化程序。


格式化

不像pprint。Pprint, prettyformatter更多地垂直传播,并尝试更多地对齐项目。

与json。转储,prettyformatter通常更紧凑,并尝试在合理的地方对齐字典值。

from prettyformatter import pprint

batters = [
    {"id": "1001", "type": "Regular"},
    {"id": "1002", "type": "Chocolate"},
    {"id": "1003", "type": "Blueberry"},
    {"id": "1004", "type": "Devil's Food"},
]

toppings = [
    {"id": "5001", "type": None},
    {"id": "5002", "type": "Glazed"},
    {"id": "5005", "type": "Sugar"},
    {"id": "5007", "type": "Powdered Sugar"},
    {"id": "5006", "type": "Chocolate with Sprinkles"},
    {"id": "5003", "type": "Chocolate"},
    {"id": "5004", "type": "Maple"},
]

data = {"id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55, "batters": batters, "topping": toppings}

pprint(data)

输出:

{
    "id"    : "0001",
    "type"  : "donut",
    "name"  : "Cake",
    "ppu"   : 0.55,
    "batters":
        [
            {"id": "1001", "type": "Regular"},
            {"id": "1002", "type": "Chocolate"},
            {"id": "1003", "type": "Blueberry"},
            {"id": "1004", "type": "Devil's Food"},
        ],
    "topping":
        [
            {"id": "5001", "type": None},
            {"id": "5002", "type": "Glazed"},
            {"id": "5005", "type": "Sugar"},
            {"id": "5007", "type": "Powdered Sugar"},
            {"id": "5006", "type": "Chocolate with Sprinkles"},
            {"id": "5003", "type": "Chocolate"},
            {"id": "5004", "type": "Maple"},
        ],
}

特性

请在这里查看完整的文档。

JSON

不像pprint。pprint, prettyformatter通过JSON =True参数支持JSON转换。这包括将None更改为null, True更改为True, False更改为False,以及正确使用引号。

与json。转储,prettyformatter支持更多数据类型的JSON强制。这包括将任何数据类或映射更改为字典,将任何可迭代对象更改为列表。

from dataclasses import dataclass

from prettyformatter import PrettyDataclass, pprint


@dataclass(unsafe_hash=True)
class Point(PrettyDataclass):
    x: int
    y: int


pprint((Point(1, 2), Point(3, 4)), json=True)

输出:

[{"x": 1, "y": 2}, {"x": 3, "y": 4}]

定制

不像pprint。Pprint或json。转储,prettyformatter支持轻松定制附加类型。

为一个prettyformatter实现__pargs__和/或__pkwargs__方法。PrettyClass子类允许用户以“cls_name(*args, **kwargs)”的形式轻松地自定义类。

from prettyformatter import PrettyClass


class Dog(PrettyClass):

    def __init__(self, name, **kwargs):
        self.name = name

    def __pkwargs__(self):
        return {"name": self.name}


print(Dog("Fido"))
"""
Dog(name="Fido")
"""

print(Dog("Fido"), json=True)
"""
{"name": "Fido"}
"""

实现__pformat__方法可以实现更具体的pformat函数。

实现@prettyformatter。Register函数还允许以与实现__pformat__相同的方式自定义已经存在的类。

import numpy as np
from prettyformatter import pprint, register

@register(np.ndarray)
def pformat_ndarray(obj, specifier, depth, indent, shorten, json):
    if json:
        return pformat(obj.tolist(), specifier, depth, indent, shorten, json)
    with np.printoptions(formatter=dict(all=lambda x: format(x, specifier))):
        return repr(obj).replace("\n", "\n" + " " * depth)

pprint(dict.fromkeys("ABC", np.arange(9).reshape(3, 3)))

输出:

{
    "A":
        array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]]),
    "B":
        array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]]),
    "C":
        array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]]),
}

晚了,但是这个答案不需要任何额外的库。类似于STH的答案,但在格式上更健壮一点,并返回一个完整的字符串,然后可以打印:

def pretty_print_dict(
        input_dictionary,
        indent=1,
        depth=0
):
    # Bool flag to add comma's after first item in dict.
    needs_comma = False
    # String for any dict will start with a '{'
    return_string = '\t' * depth + '{\n'
    # Iterate over keys and values, building the full string out.
    for key, value in input_dictionary.items():
        # Start with key. If key follows a previous item, add comma.
        if needs_comma:
            return_string = return_string + ',\n' + '\t' * (depth + 1) + str(key) + ': '
        else:
            return_string = return_string + '\t' * (depth + 1) + str(key) + ': '
        # If the value is a dict, recursively call function.
        if isinstance(value, dict):
            return_string = return_string + '\n' + pretty_print_dict(value, depth=depth+2)
        else:
            return_string = return_string + '\t' * indent + str(value)
        # After first line, flip bool to True to make sure commas make it.
        needs_comma = True
    # Complete the dict with a '}'
    return_string = return_string + '\n' + '\t' * depth + '}'
    # Return dict string.
    return return_string

让我们看看它如何处理像test_dict={1,2,3:{4:{5:6}, 7:8}, 9:10}这样的字典。

字符串的样子:“{\ n \ t1: \ t2, t3: \ n \ \ n \ t \ {\ n \ t \ \ t4: \ n \ t \ t \ \ {\ n \ t \ t \ \ \ t5: \ t6 \ n \ t \ t \ \ t}, \ n \ t \ \ t7: \ t8 \ n \ t \ t}, \ n \ t9: \ t10 \ n}”。

打印该字符串会得到:

{
    1:  2,
    3: 
        {
            4: 
                {
                    5:  6
                },
            7:  8
        },
    9:  10
}

使用这个函数:

def pretty_dict(d, n=1):
    for k in d:
        print(" "*n + k)
        try:
            pretty_dict(d[k], n=n+4)
        except TypeError:
            continue

这样叫它:

pretty_dict(mydict)

正如其他人所发布的,你可以使用递归/dfs打印嵌套的字典数据,并递归调用如果它是一个字典;否则打印数据。

def print_json(data):
    if type(data) == dict:
            for k, v in data.items():
                    print k
                    print_json(v)
    else:
            print data

我自己是一个相对的python新手,但过去几周我一直在使用嵌套字典,这就是我想到的。

你应该尝试使用堆栈。将根字典中的键变成一个列表的列表:

stack = [ root.keys() ]     # Result: [ [root keys] ]

按照从最后到第一个的相反顺序,查找字典中的每个键,看看它的值是否(也是)一个字典。如果不是,打印密钥,然后删除它。但是,如果键的值是一个字典,则打印该键,然后将该值的键附加到堆栈的末尾,并以相同的方式开始处理该列表,对每个新的键列表进行递归重复。

如果每个列表中第二个键的值是一个字典,那么在几轮之后,你会得到这样的结果:

[['key 1','key 2'],['key 2.1','key 2.2'],['key 2.2.1','key 2.2.2'],[`etc.`]]

这种方法的优点是缩进只是\t乘以堆栈的长度:

indent = "\t" * len(stack)

缺点是为了检查每个键,你需要散列到相关的子字典,尽管这可以通过列表理解和简单的for循环轻松处理:

path = [li[-1] for li in stack]
# The last key of every list of keys in the stack

sub = root
for p in path:
    sub = sub[p]


if type(sub) == dict:
    stack.append(sub.keys()) # And so on

注意,这种方法将要求清除尾随的空列表,并删除后跟空列表的任何列表中的最后一个键(当然,这可能会创建另一个空列表,等等)。

还有其他方法来实现这个方法,但希望这能给你一个基本的想法。

编辑:如果您不想进行所有这些操作,pprint模块将以良好的格式打印嵌套字典。