110

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

直到他们在 Python 2.7 中添加了新的有序字典类型(我非常喜欢的另一个很酷的特性)之前,它一直运行良好。如果我尝试漂亮地打印有序字典,它不会很好地显示。不是将每个键值对放在自己的行中,而是将整个内容显示在一行很长的行中,该行包含很多次并且难以阅读:

>>> from collections import OrderedDict
>>> o = OrderedDict([("aaaaa", 1), ("bbbbbb", 2), ("ccccccc", 3), ("dddddd", 4), ("eeeeee", 5), ("ffffff", 6), ("ggggggg", 7)])
>>> import pprint
>>> pprint.pprint(o)
OrderedDict([('aaaaa', 1), ('bbbbbb', 2), ('ccccccc', 3), ('dddddd', 4), ('eeeeee', 5), ('ffffff', 6), ('ggggggg', 7)])

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

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

4

15 回答 15

145

从 Python 3.7 开始,Python 保证字典中的键将保留其插入顺序。(尽管它们的行为仍然与对象不完全相同OrderedDict,作为两个 dictsa并且即使键的顺序不同b也可以被认为是相等的,而在测试相等性时会检查这一点。)a == bOrderedDict

Python 3.8 或更新版本:

您可以使用sort_dicts=False它来防止它按字母顺序对它们进行排序:

>>> example_dict = {'x': 1, 'b': 2, 'm': 3}
>>> import pprint
>>> pprint.pprint(example_dict, sort_dicts=False)
{'x': 1, 'b': 2, 'm': 3}

Python 3.7 或更早版本:

作为临时解决方法,您可以尝试以 JSON 格式转储,而不是使用pprint.

您丢失了一些类型信息,但它看起来不错并保持顺序。

>>> import json
>>> print(json.dumps(example_dict, indent=4))
{
    "x": 1,
    "b": 2,
    "m": 3
}
于 2011-02-04T12:33:49.767 回答
17

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

>>> from collections import OrderedDict
>>> o = OrderedDict([("aaaaa", 1), ("bbbbbb", 2), ("ccccccc", 3), ("dddddd", 4), ("eeeeee", 5), ("ffffff", 6), ("ggggggg", 7)])
>>> import pprint
>>> pprint.pprint(dict(o.items()))
{'aaaaa': 1,
 'bbbbbb': 2,
 'ccccccc': 3,
 'dddddd': 4,
 'eeeeee': 5,
 'ffffff': 6,
 'ggggggg': 7}

从 Python 3.7 开始,Python 保证字典中的键将保留其插入顺序。因此,如果您使用的是 Python 3.7+,则无需确保 OrderedDict 是按字母顺序排序的。

于 2010-11-29T05:51:55.903 回答
9

这是通过在内部覆盖和使用 stockpprint()函数来工作的另一个答案。与我之前的版本不同,它将在另一个容器(例如 a)中处理 ' ,并且还应该能够处理给定的任何可选关键字参数——但是它对另一个容器提供的输出的控制程度不同。OrderedDictlist

它通过将 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)])]

于 2010-11-29T13:04:10.970 回答
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)
]))
于 2015-03-05T19:46:33.680 回答
5

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

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

from collections import OrderedDict
import pprint

class ItemKey(object):
  def __init__(self, name, position):
    self.name = name
    self.position = position
  def __cmp__(self, b):
    assert isinstance(b, ItemKey)
    return cmp(self.position, b.position)
  def __repr__(self):
    return repr(self.name)

OrderedDict.items = lambda self: [
    (ItemKey(name, i), value)
    for i, (name, value) in enumerate(self.iteritems())]
OrderedDict.__repr__ = dict.__repr__

a = OrderedDict()
a[4] = '4'
a[1] = '1'
a[2] = '2'
print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'}
于 2015-08-24T17:26:18.270 回答
3

这是我漂亮打印 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"
}
于 2018-08-10T20:25:05.817 回答
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)
于 2010-11-29T05:33:54.960 回答
2

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

我的目标是使用简洁的 python 代码实现几乎类似 yaml 的输出,但并没有成功。

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 和 OrderedDict 列表的测试数据......(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() 进行更好对齐的过程中,我有一些想法,但不想深入研究它。您需要根据所需的对齐类型动态指定字段宽度,这会变得棘手或繁琐。

无论如何,这以可读的分层方式向我展示了我的数据,所以这对我有用!

于 2014-02-15T07:54:00.947 回答
2

我已经在 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 的摘要,并在调用期间禁用排序,以便实际上没有对键进行排序以进行打印。

于 2019-04-05T20:12:28.077 回答
2

从 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

于 2019-11-02T19:48:47.760 回答
2

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

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

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

于 2016-12-09T11:11:14.633 回答
1

pprint()方法只是调用其中__repr__()事物的方法,并且OrderedDict在它的方法中似乎没有做太多事情(或者没有一个或什么)。

如果您不关心 PPRINT 输出中的订单是否可见,这是一个便宜的解决方案应该可以工作,如果:

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

我真的很惊讶订单没有被保留……嗯。

于 2012-02-03T16:53:07.793 回答
1

较新版本的 Python 3 没有您提到的问题。当您pprint使用 OrderedDict 时,如果有足够的键值对,它会将每个键值对包装在单独的行上,而不是包装:

>>> from collections import OrderedDict
>>> o = OrderedDict([("aaaaa", 1), ("bbbbbb", 2), ("ccccccc", 3), ("dddddd", 4), ("eeeeee", 5), ("ffffff", 6), ("ggggggg", 7)])
>>> import pprint
>>> pprint.pprint(o)
OrderedDict([('aaaaa', 1),
             ('bbbbbb', 2),
             ('ccccccc', 3),
             ('dddddd', 4),
             ('eeeeee', 5),
             ('ffffff', 6),
             ('ggggggg', 7)])

Python 2.7 会将所有内容放在一行上,但 Python 3 不会。

于 2021-09-29T16:11:48.397 回答
0

您可以重新定义pprint()和拦截对OrderedDict's 的调用。这是一个简单的例子。如所写,OrderedDict覆盖代码忽略任何可能已传递的可选、、、或关键字,但可以对其进行增强以stream实现它们indent。不幸的是,这种技术不能在另一个容器中处理它们,例如 a of 'swidthdepthlistOrderDict

from collections import OrderedDict
from pprint import pprint as pp_pprint

def pprint(obj, *args, **kwrds):
    if not isinstance(obj, OrderedDict):
        # use stock function
        return pp_pprint(obj, *args, **kwrds)
    else:
        # very simple sample custom implementation...
        print "{"
        for key in obj:
            print "    %r:%r" % (key, obj[key])
        print "}"

l = [10, 2, 4]
d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
pprint(l, width=4)
# [10,
#  2,
#  4]
pprint(d)
# {'john': 1, 'mary': 3, 'paul': 2}

pprint(od)
# {
#     'john':1
#     'paul':2
#     'mary':3
# }
于 2010-11-29T10:05:10.727 回答
0

对于 python < 3.8(例如 3.6):

Monkey patchpprintsorted为了防止它被排序。这也将具有递归工作的所有好处,并且比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}}

编辑:清理

要在这个肮脏的业务之后进行清理,只需运行: pprint.sorted = sorted

对于一个真正干净的解决方案,甚至可以使用上下文管理器:

import pprint
import contextlib

@contextlib.contextmanager
def pprint_ordered():
    pprint.sorted = lambda arg, *args, **kwargs: arg
    yield
    pprint.sorted = sorted

# usage:

with pprint_ordered():
    pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)

# without it    
pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)

# prints: 
#    
# {'z': 1,
#  'a': 2,
#  'c': {'z': 0,
#        'a': 1}}
#
# {'a': 2,
#  'c': {'a': 1,
#        'z': 0},
#  'z': 1}
于 2020-03-18T10:15:28.803 回答