有没有什么方法可以正确地打印有序的词典?

时间:2010-11-29 05:27:27

标签: python python-2.7 pretty-print ordereddictionary pprint

我喜欢Python中的pprint模块。我经常使用它进行测试和调试。我经常使用width选项来确保输出很好地适合我的终端窗口。

它一直运行良好,直到他们在Python 2.7中添加了新的ordered dictionary type(我非常喜欢的另一个很酷的功能)。如果我试着漂亮地打印一个有序的字典,它就不能很好地显示出来。而不是让每个键值对都在它自己的行上,整个事物显示在一条长行上,它包含很多次并且难以阅读。

有没有人有办法让它打印得很好,就像旧的无序词典一样?如果我花了足够的时间,我可能会想出一些东西,可能使用PrettyPrinter.format方法,但我想知道这里是否有人知道解决方案。

更新:我已为此提交了错误报告。你可以在http://bugs.python.org/issue10592看到它。

15 个答案:

答案 0 :(得分:120)

作为临时解决方法,您可以尝试以JSON格式转储。 你丢失了一些类型信息,但它看起来不错并保持秩序。

import json

pprint(data, indent=4)
# ^ugly

print(json.dumps(data, indent=4))
# ^nice

答案 1 :(得分:14)

如果您的OrderedDict的顺序是alpha排序,则以下内容将起作用,因为pprint将在打印前对dict进行排序。

pprint(dict(o.items()))

答案 2 :(得分:8)

这是另一个通过在内部覆盖和使用股票pprint()功能的答案。与我的earlier one不同,处理OrderedDict在另一个容器(例如list)中,并且还应该能够处理给定的任何可选关键字参数 - 但是它对另一方提供的输出没有相同程度的控制。

它通过将stock函数的输出重定向到临时缓冲区然后在将其发送到输出流之前将其换行来进行操作。虽然产生的最终输出并不是特别漂亮,但是它可以“足够好”用作解决方法。

更新2.0

通过使用标准库textwrap模块进行简化,并进行了修改以便工作 Python 2& 3。

from collections import OrderedDict
try:
    from cStringIO import StringIO
except ImportError:  # Python 3
    from io import StringIO
from pprint import pprint as pp_pprint
import sys
import textwrap

def pprint(object, **kwrds):
    try:
        width = kwrds['width']
    except KeyError: # unlimited, use stock function
        pp_pprint(object, **kwrds)
        return
    buffer = StringIO()
    stream = kwrds.get('stream', sys.stdout)
    kwrds.update({'stream': buffer})
    pp_pprint(object, **kwrds)
    words = buffer.getvalue().split()
    buffer.close()

    # word wrap output onto multiple lines <= width characters
    try:
        print >> stream, textwrap.fill(' '.join(words), width=width)
    except TypeError:  # Python 3
        print(textwrap.fill(' '.join(words), width=width), file=stream)

d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))),
       OrderedDict((('moe',1), ('curly',2), ('larry',3))),
       OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))]

示例输出:

pprint(d, width=40)

»{'john': 1, 'mary': 3, 'paul': 2}

pprint(od, width=40)

»OrderedDict([('john', 1), ('paul', 2),
('mary', 3)])

pprint(lod, width=40)

»[OrderedDict([('john', 1), ('paul', 2),
('mary', 3)]), OrderedDict([('moe', 1),
('curly', 2), ('larry', 3)]),
OrderedDict([('weapons', 1), ('mass',
2), ('destruction', 3)])]

答案 3 :(得分:7)

打印有序的字典,例如

from collections import OrderedDict

d=OrderedDict([
    ('a', OrderedDict([
        ('a1',1),
        ('a2','sss')
    ])),
    ('b', OrderedDict([
        ('b1', OrderedDict([
            ('bb1',1),
            ('bb2',4.5)])),
        ('b2',4.5)
    ])),
])

我做

def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0):
    def is_number(s):
        try:
            float(s)
            return True
        except ValueError:
            return False
    def fstr(s):
        return s if is_number(s) else '"%s"'%s
    if mode != 'dict':
        kv_tpl = '("%s", %s)'
        ST = 'OrderedDict([\n'; END = '])'
    else:
        kv_tpl = '"%s": %s'
        ST = '{\n'; END = '}'
    for i,k in enumerate(OD.keys()):
        if type(OD[k]) in [dict, OrderedDict]:
            level += 1
            s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END)
            level -= 1
        else:
            s += level*indent+kv_tpl%(k,fstr(OD[k]))
        if i!=len(OD)-1:
            s += ","
        s += "\n"
    return s

print dict_or_OrdDict_to_formatted_str(d)

哪个收益

"a": {
    "a1": 1,
    "a2": "sss"
},
"b": {
    "b1": {
        "bb1": 1,
        "bb2": 4.5
    },
    "b2": 4.5
}

print dict_or_OrdDict_to_formatted_str(d, mode='OD')

产生

("a", OrderedDict([
    ("a1", 1),
    ("a2", "sss")
])),
("b", OrderedDict([
    ("b1", OrderedDict([
        ("bb1", 1),
        ("bb2", 4.5)
    ])),
    ("b2", 4.5)
]))

答案 4 :(得分:5)

这是一种破解lwd=实施的方法。 pprint在打印前对键进行排序,因此为了保持顺序,我们只需按照我们想要的方式对键进行排序。

请注意,这会影响pprint功能。 因此,您可能希望在执行pprint后保留并恢复被覆盖的函数。

items()

答案 5 :(得分:2)

def pprint_od(od):
    print "{"
    for key in od:
        print "%s:%s,\n" % (key, od[key]) # Fixed syntax
    print "}"

你去^^

for item in li:
    pprint_od(item)

(pprint_od(item) for item in li)

答案 6 :(得分:2)

这很粗糙,但我只需要一种可视化由任意映射和Iterables组成的数据结构的方法,这就是我在放弃之前提出的。它是递归的,因此它将通过嵌套结构和列表很好地落下。我使用集合中的Mapping和Iterable抽象基类来处理任何事情。

我的目标是使用简洁的python代码,几乎像yuml一样输出,但是并没有完全实现它。

def format_structure(d, level=0):
    x = ""
    if isinstance(d, Mapping):
        lenk = max(map(lambda x: len(str(x)), d.keys()))
        for k, v in d.items():
            key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k)
            x += key_text + ": " + format_structure(v, level=level+lenk)
    elif isinstance(d, Iterable) and not isinstance(d, basestring):
        for e in d:
            x += "\n" + " "*level + "- " + format_structure(e, level=level+4)
    else:
        x = str(d)
    return x

和一些使用OrderedDict的测试数据和OrderedDicts列表......(sheesh Python需要OrderedDict文字太糟糕......)

d = OrderedDict([("main",
                  OrderedDict([("window",
                                OrderedDict([("size", [500, 500]),
                                             ("position", [100, 900])])),
                               ("splash_enabled", True),
                               ("theme", "Dark")])),
                 ("updates",
                  OrderedDict([("automatic", True),
                               ("servers",
                                [OrderedDict([("url", "http://server1.com"),
                                              ("name", "Stable")]),
                                 OrderedDict([("url", "http://server2.com"),
                                              ("name", "Beta")]),
                                 OrderedDict([("url", "http://server3.com"),
                                              ("name", "Dev")])]),
                               ("prompt_restart", True)])),
                 ("logging",
                  OrderedDict([("enabled", True),
                               ("rotate", True)]))])

print format_structure(d)

产生以下输出:

   main: 
               window: 
                         size: 
                             - 500
                             - 500
                     position: 
                             - 100
                             - 900
       splash_enabled: True
                theme: Dark
updates: 
            automatic: True
              servers: 
                     - 
                          url: http://server1.com
                         name: Stable
                     - 
                          url: http://server2.com
                         name: Beta
                     - 
                          url: http://server3.com
                         name: Dev
       prompt_restart: True
logging: 
       enabled: True
        rotate: True

我在使用str.format()方面有一些想法,以便更好地对齐,但不想深入研究它。您需要根据所需的对齐类型动态指定字段宽度,这会变得棘手或麻烦。

无论如何,这以可读的分层方式向我显示我的数据,因此对我有用!

答案 7 :(得分:1)

pprint()方法只是调用其中的__repr__()方法,而OrderedDict似乎没有在它的方法中做太多(或没有一个或一个东西) )。

这是一个廉价的解决方案应该可以正常工作如果你不关心在PPRINT OUTPUT中可见的顺序,这可能是一个很大的if:

class PrintableOrderedDict(OrderedDict):
    def __repr__(self):
        return dict.__repr__(self)

我真的很惊讶订单没有保存......好啊。

答案 8 :(得分:1)

您还可以使用kzh答案的简化:

pprint(data.items(), indent=4)

它保留了订单,输出几乎与webwurst答案相同(通过json转储打印)。

答案 9 :(得分:1)

我已经在python3.5上测试了这个基于邪恶的猴子补丁的黑客,并且可以正常工作:

pprint.PrettyPrinter._dispatch[pprint._collections.OrderedDict.__repr__] = pprint.PrettyPrinter._pprint_dict


def unsorted_pprint(data):
    def fake_sort(*args, **kwargs):
        return args[0]
    orig_sorted = __builtins__.sorted
    try:
        __builtins__.sorted = fake_sort
        pprint.pprint(data)
    finally:
        __builtins__.sorted = orig_sorted

您使pprint使用基于常规dict的摘要,并在通话过程中禁用排序功能,这样就不会为打印实际排序任何键。

答案 10 :(得分:1)

从python 3.8开始:pprint.PrettyPrinter公开了sort_dicts关键字参数。

默认情况下

True ,将其设置为 False 将使字典保持未排序状态。

>>> from pprint import PrettyPrinter

>>> x = {'John': 1,
>>>      'Mary': 2,
>>>      'Paul': 3,
>>>      'Lisa': 4,
>>>      }

>>> PrettyPrinter(sort_dicts=False).pprint(x)

将输出:

{'John': 1, 
 'Mary': 2, 
 'Paul': 3,
 'Lisa': 4}

参考:https://docs.python.org/3/library/pprint.html

答案 11 :(得分:1)

对于python <3.8(例如3.6):

猴子补丁pprint的{​​{1}},以防止其排序。 这也将使所有内容都可以递归工作,并且比sorted选项更适合需要使用例如json参数:

width

编辑:清理

要清理此肮脏的业务后,请运行: import pprint pprint.sorted = lambda arg, *a, **kw: arg >>> pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20) {'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}

对于真正干净的解决方案,甚至可以使用contextmanager:

pprint.sorted = sorted

答案 12 :(得分:0)

您可以重新定义pprint()并拦截OrderedDict的来电。这是一个简单的例子。如上所述,OrderedDict覆盖代码会忽略可能已传递的任何可选streamindentwidthdepth个关键字,但可以增强为实施它们。不幸的是,这种技术不会在另一个容器中处理它们,例如list的{​​{1}}

OrderDict

答案 13 :(得分:0)

如果字典项都是一种类型,您可以使用令人惊叹的数据处理库pandas

>>> import pandas as pd
>>> x = {'foo':1, 'bar':2}
>>> pd.Series(x)
bar    2
foo    1
dtype: int64

>>> import pandas as pd
>>> x = {'foo':'bar', 'baz':'bam'}
>>> pd.Series(x)
baz    bam
foo    bar
dtype: object

答案 14 :(得分:0)

这是我漂亮打印OrderedDict的方法

from collections import OrderedDict
import json
d = OrderedDict()
d['duck'] = 'alive'
d['parrot'] = 'dead'
d['penguin'] = 'exploded'
d['Falcon'] = 'discharged'
print d
print json.dumps(d,indent=4)

OutPut:

OrderedDict([('duck', 'alive'), ('parrot', 'dead'), ('penguin', 'exploded'), ('Falcon', 'discharged')])

{
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded",
    "Falcon": "discharged"
}

如果您要按顺序漂亮地打印带有键的字典

print json.dumps(indent=4,sort_keys=True)
{
    "Falcon": "discharged",
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded"
}